1 // Copyright 2008 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <cstddef> 9 #include <map> 10 #include <memory> 11 #include <optional> 12 #include <set> 13 #include <string> 14 #include <variant> 15 #include <vector> 16 17 #include "Common/CommonTypes.h" 18 #include "Common/FileUtil.h" 19 #include "DiscIO/Blob.h" 20 #include "DiscIO/WiiEncryptionCache.h" 21 22 namespace File 23 { 24 struct FSTEntry; 25 class IOFile; 26 } // namespace File 27 28 namespace DiscIO 29 { 30 enum class PartitionType : u32; 31 32 class DirectoryBlobReader; 33 34 // Returns true if the path is inside a DirectoryBlob and doesn't represent the DirectoryBlob itself 35 bool ShouldHideFromGameList(const std::string& volume_path); 36 37 class DiscContent 38 { 39 public: 40 using ContentSource = 41 std::variant<std::string, // File 42 const u8*, // Memory 43 DirectoryBlobReader* // Partition (which one it is is determined by m_offset) 44 >; 45 46 DiscContent(u64 offset, u64 size, const std::string& path); 47 DiscContent(u64 offset, u64 size, const u8* data); 48 DiscContent(u64 offset, u64 size, DirectoryBlobReader* blob); 49 50 // Provided because it's convenient when searching for DiscContent in an std::set 51 explicit DiscContent(u64 offset); 52 53 u64 GetOffset() const; 54 u64 GetEndOffset() const; 55 u64 GetSize() const; 56 bool Read(u64* offset, u64* length, u8** buffer) const; 57 58 bool operator==(const DiscContent& other) const { return GetEndOffset() == other.GetEndOffset(); } 59 bool operator!=(const DiscContent& other) const { return !(*this == other); } 60 bool operator<(const DiscContent& other) const { return GetEndOffset() < other.GetEndOffset(); } 61 bool operator>(const DiscContent& other) const { return other < *this; } 62 bool operator<=(const DiscContent& other) const { return !(*this < other); } 63 bool operator>=(const DiscContent& other) const { return !(*this > other); } 64 65 private: 66 u64 m_offset; 67 u64 m_size = 0; 68 ContentSource m_content_source; 69 }; 70 71 class DiscContentContainer 72 { 73 public: 74 template <typename T> Add(u64 offset,const std::vector<T> & vector)75 void Add(u64 offset, const std::vector<T>& vector) 76 { 77 return Add(offset, vector.size() * sizeof(T), reinterpret_cast<const u8*>(vector.data())); 78 } 79 void Add(u64 offset, u64 size, const std::string& path); 80 void Add(u64 offset, u64 size, const u8* data); 81 void Add(u64 offset, u64 size, DirectoryBlobReader* blob); 82 u64 CheckSizeAndAdd(u64 offset, const std::string& path); 83 u64 CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path); 84 85 bool Read(u64 offset, u64 length, u8* buffer) const; 86 87 private: 88 std::set<DiscContent> m_contents; 89 }; 90 91 class DirectoryBlobPartition 92 { 93 public: 94 DirectoryBlobPartition() = default; 95 DirectoryBlobPartition(const std::string& root_directory, std::optional<bool> is_wii); 96 97 // We do not allow copying, because it might mess up the pointers inside DiscContents 98 DirectoryBlobPartition(const DirectoryBlobPartition&) = delete; 99 DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = delete; 100 DirectoryBlobPartition(DirectoryBlobPartition&&) = default; 101 DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default; 102 IsWii()103 bool IsWii() const { return m_is_wii; } GetDataSize()104 u64 GetDataSize() const { return m_data_size; } GetRootDirectory()105 const std::string& GetRootDirectory() const { return m_root_directory; } GetHeader()106 const std::vector<u8>& GetHeader() const { return m_disc_header; } GetContents()107 const DiscContentContainer& GetContents() const { return m_contents; } 108 GetKey()109 const std::array<u8, VolumeWii::AES_KEY_SIZE>& GetKey() const { return m_key; } SetKey(std::array<u8,VolumeWii::AES_KEY_SIZE> key)110 void SetKey(std::array<u8, VolumeWii::AES_KEY_SIZE> key) { m_key = key; } 111 112 private: 113 void SetDiscHeaderAndDiscType(std::optional<bool> is_wii); 114 void SetBI2(); 115 116 // Returns DOL address 117 u64 SetApploader(); 118 // Returns FST address 119 u64 SetDOL(u64 dol_address); 120 121 void BuildFST(u64 fst_address); 122 123 // FST creation 124 void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, 125 u32 address_shift); 126 void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset); 127 void WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, u32* name_offset, 128 u64* data_offset, u32 parent_entry_index, u64 name_table_offset); 129 130 DiscContentContainer m_contents; 131 std::vector<u8> m_disc_header; 132 std::vector<u8> m_bi2; 133 std::vector<u8> m_apploader; 134 std::vector<u8> m_fst_data; 135 136 std::array<u8, VolumeWii::AES_KEY_SIZE> m_key; 137 138 std::string m_root_directory; 139 bool m_is_wii = false; 140 // GameCube has no shift, Wii has 2 bit shift 141 u32 m_address_shift = 0; 142 143 u64 m_data_size; 144 }; 145 146 class DirectoryBlobReader : public BlobReader 147 { 148 friend DiscContent; 149 150 public: 151 static std::unique_ptr<DirectoryBlobReader> Create(const std::string& dol_path); 152 153 // We do not allow copying, because it might mess up the pointers inside DiscContents 154 DirectoryBlobReader(const DirectoryBlobReader&) = delete; 155 DirectoryBlobReader& operator=(const DirectoryBlobReader&) = delete; 156 DirectoryBlobReader(DirectoryBlobReader&&) = default; 157 DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default; 158 159 bool Read(u64 offset, u64 length, u8* buffer) override; 160 bool SupportsReadWiiDecrypted(u64 offset, u64 size, u64 partition_data_offset) const override; 161 bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_data_offset) override; 162 163 BlobType GetBlobType() const override; 164 165 u64 GetRawSize() const override; 166 u64 GetDataSize() const override; IsDataSizeAccurate()167 bool IsDataSizeAccurate() const override { return true; } 168 GetBlockSize()169 u64 GetBlockSize() const override { return 0; } HasFastRandomAccessInBlock()170 bool HasFastRandomAccessInBlock() const override { return true; } GetCompressionMethod()171 std::string GetCompressionMethod() const override { return {}; } 172 173 private: 174 struct PartitionWithType 175 { PartitionWithTypePartitionWithType176 PartitionWithType(DirectoryBlobPartition&& partition_, PartitionType type_) 177 : partition(std::move(partition_)), type(type_) 178 { 179 } 180 181 DirectoryBlobPartition partition; 182 PartitionType type; 183 }; 184 185 explicit DirectoryBlobReader(const std::string& game_partition_root, 186 const std::string& true_root); 187 188 const DirectoryBlobPartition* GetPartition(u64 offset, u64 size, u64 partition_data_offset) const; 189 190 bool EncryptPartitionData(u64 offset, u64 size, u8* buffer, u64 partition_data_offset, 191 u64 partition_data_decrypted_size); 192 193 void SetNonpartitionDiscHeader(const std::vector<u8>& partition_header, 194 const std::string& game_partition_root); 195 void SetWiiRegionData(const std::string& game_partition_root); 196 void SetPartitions(std::vector<PartitionWithType>&& partitions); 197 void SetPartitionHeader(DirectoryBlobPartition* partition, u64 partition_address); 198 199 // For GameCube: 200 DirectoryBlobPartition m_gamecube_pseudopartition; 201 202 // For Wii: 203 DiscContentContainer m_nonpartition_contents; 204 std::map<u64, DirectoryBlobPartition> m_partitions; 205 WiiEncryptionCache m_encryption_cache; 206 207 bool m_is_wii; 208 bool m_encrypted; 209 210 std::vector<u8> m_disc_header_nonpartition; 211 std::vector<u8> m_partition_table; 212 std::vector<u8> m_wii_region_data; 213 std::vector<std::vector<u8>> m_partition_headers; 214 215 u64 m_data_size; 216 }; 217 218 } // namespace DiscIO 219