// Copyright 2008 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include #include #include #include #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "DiscIO/Blob.h" #include "DiscIO/WiiEncryptionCache.h" namespace File { struct FSTEntry; class IOFile; } // namespace File namespace DiscIO { enum class PartitionType : u32; class DirectoryBlobReader; // Returns true if the path is inside a DirectoryBlob and doesn't represent the DirectoryBlob itself bool ShouldHideFromGameList(const std::string& volume_path); class DiscContent { public: using ContentSource = std::variant; DiscContent(u64 offset, u64 size, const std::string& path); DiscContent(u64 offset, u64 size, const u8* data); DiscContent(u64 offset, u64 size, DirectoryBlobReader* blob); // Provided because it's convenient when searching for DiscContent in an std::set explicit DiscContent(u64 offset); u64 GetOffset() const; u64 GetEndOffset() const; u64 GetSize() const; bool Read(u64* offset, u64* length, u8** buffer) const; bool operator==(const DiscContent& other) const { return GetEndOffset() == other.GetEndOffset(); } bool operator!=(const DiscContent& other) const { return !(*this == other); } bool operator<(const DiscContent& other) const { return GetEndOffset() < other.GetEndOffset(); } bool operator>(const DiscContent& other) const { return other < *this; } bool operator<=(const DiscContent& other) const { return !(*this < other); } bool operator>=(const DiscContent& other) const { return !(*this > other); } private: u64 m_offset; u64 m_size = 0; ContentSource m_content_source; }; class DiscContentContainer { public: template void Add(u64 offset, const std::vector& vector) { return Add(offset, vector.size() * sizeof(T), reinterpret_cast(vector.data())); } void Add(u64 offset, u64 size, const std::string& path); void Add(u64 offset, u64 size, const u8* data); void Add(u64 offset, u64 size, DirectoryBlobReader* blob); u64 CheckSizeAndAdd(u64 offset, const std::string& path); u64 CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); bool Read(u64 offset, u64 length, u8* buffer) const; private: std::set m_contents; }; class DirectoryBlobPartition { public: DirectoryBlobPartition() = default; DirectoryBlobPartition(const std::string& root_directory, std::optional is_wii); // We do not allow copying, because it might mess up the pointers inside DiscContents DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = delete; DirectoryBlobPartition(DirectoryBlobPartition&&) = default; DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default; bool IsWii() const { return m_is_wii; } u64 GetDataSize() const { return m_data_size; } const std::string& GetRootDirectory() const { return m_root_directory; } const std::vector& GetHeader() const { return m_disc_header; } const DiscContentContainer& GetContents() const { return m_contents; } const std::array& GetKey() const { return m_key; } void SetKey(std::array key) { m_key = key; } private: void SetDiscHeaderAndDiscType(std::optional is_wii); void SetBI2(); // Returns DOL address u64 SetApploader(); // Returns FST address u64 SetDOL(u64 dol_address); void BuildFST(u64 fst_address); // FST creation void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, u32 address_shift); void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset); void WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index, u64 name_table_offset); DiscContentContainer m_contents; std::vector m_disc_header; std::vector m_bi2; std::vector m_apploader; std::vector m_fst_data; std::array m_key; std::string m_root_directory; bool m_is_wii = false; // GameCube has no shift, Wii has 2 bit shift u32 m_address_shift = 0; u64 m_data_size; }; class DirectoryBlobReader : public BlobReader { friend DiscContent; public: static std::unique_ptr Create(const std::string& dol_path); // We do not allow copying, because it might mess up the pointers inside DiscContents DirectoryBlobReader(const DirectoryBlobReader&) = delete; DirectoryBlobReader& operator=(const DirectoryBlobReader&) = delete; DirectoryBlobReader(DirectoryBlobReader&&) = default; DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default; bool Read(u64 offset, u64 length, u8* buffer) override; bool SupportsReadWiiDecrypted() const override; bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_data_offset) override; BlobType GetBlobType() const override; u64 GetRawSize() const override; u64 GetDataSize() const override; bool IsDataSizeAccurate() const override { return true; } u64 GetBlockSize() const override { return 0; } bool HasFastRandomAccessInBlock() const override { return true; } private: struct PartitionWithType { PartitionWithType(DirectoryBlobPartition&& partition_, PartitionType type_) : partition(std::move(partition_)), type(type_) { } DirectoryBlobPartition partition; PartitionType type; }; explicit DirectoryBlobReader(const std::string& game_partition_root, const std::string& true_root); bool EncryptPartitionData(u64 offset, u64 size, u8* buffer, u64 partition_data_offset, u64 partition_data_decrypted_size); void SetNonpartitionDiscHeader(const std::vector& partition_header, const std::string& game_partition_root); void SetWiiRegionData(const std::string& game_partition_root); void SetPartitions(std::vector&& partitions); void SetPartitionHeader(DirectoryBlobPartition* partition, u64 partition_address); // For GameCube: DirectoryBlobPartition m_gamecube_pseudopartition; // For Wii: DiscContentContainer m_nonpartition_contents; std::map m_partitions; WiiEncryptionCache m_encryption_cache; bool m_is_wii; bool m_encrypted; std::vector m_disc_header_nonpartition; std::vector m_partition_table; std::vector m_wii_region_data; std::vector> m_partition_headers; u64 m_data_size; }; } // namespace DiscIO