// Copyright Citra Emulator Project / Azahar 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/alignment.h" #include "common/common_types.h" #include "common/file_util.h" #include "common/static_lru_cache.h" #include "core/file_sys/artic_cache.h" #include "network/artic_base/artic_base_client.h" namespace Loader { enum class ResultStatus; } namespace FileSys { /** * Interface for reading RomFS data. */ class RomFSReader { public: virtual ~RomFSReader() = default; virtual std::size_t GetSize() const = 0; virtual std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) = 0; virtual bool AllowsCachedReads() const = 0; virtual bool CacheReady(std::size_t file_offset, std::size_t length) = 0; private: template void serialize(Archive& ar, const unsigned int file_version) {} friend class boost::serialization::access; }; /** * A RomFS reader that directly reads the RomFS file. */ class DirectRomFSReader : public RomFSReader { public: DirectRomFSReader(std::unique_ptr&& file, std::size_t file_offset, std::size_t data_size) : file(std::move(file)), file_offset(file_offset), data_size(data_size) {} ~DirectRomFSReader() override = default; std::size_t GetSize() const override { return data_size; } std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) override; bool AllowsCachedReads() const override; bool CacheReady(std::size_t file_offset, std::size_t length) override; private: std::unique_ptr file; u64 file_offset; u64 data_size; // Total cache size: 128KB static constexpr std::size_t cache_line_size = (1 << 13); // About 8KB static constexpr std::size_t cache_line_count = 16; Common::StaticLRUCache, cache_line_count> cache; // TODO(PabloMK7): Make cache thread safe, read the comment in CacheReady function. // std::shared_mutex cache_mutex; DirectRomFSReader() = default; std::size_t OffsetToPage(std::size_t offset) { return Common::AlignDown(offset, cache_line_size); } std::vector> BreakupRead(std::size_t offset, std::size_t length); template void serialize(Archive& ar, const unsigned int) { ar& boost::serialization::base_object(*this); ar & file; ar & file_offset; ar & data_size; } friend class boost::serialization::access; }; /** * A RomFS reader that reads from an artic base server. */ class ArticRomFSReader : public RomFSReader { public: ArticRomFSReader() = default; ArticRomFSReader(std::shared_ptr& cli, bool is_update_romfs); ~ArticRomFSReader() override; std::size_t GetSize() const override { return data_size; } std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) override; bool AllowsCachedReads() const override; bool CacheReady(std::size_t file_offset, std::size_t length) override; Loader::ResultStatus OpenStatus() { return load_status; } void ClearCache() { cache.Clear(); } void CloseFile(); private: std::shared_ptr client; size_t data_size = 0; s32 romfs_handle = -1; Loader::ResultStatus load_status; ArticCache cache; template void serialize(Archive& ar, const unsigned int) { ar& boost::serialization::base_object(*this); ar & data_size; } friend class boost::serialization::access; }; } // namespace FileSys BOOST_CLASS_EXPORT_KEY(FileSys::DirectRomFSReader) BOOST_CLASS_EXPORT_KEY(FileSys::ArticRomFSReader)