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 <cstring> 8 #include <limits> 9 #include <map> 10 #include <memory> 11 #include <optional> 12 #include <string> 13 #include <vector> 14 15 #include <mbedtls/sha1.h> 16 17 #include "Common/CommonTypes.h" 18 #include "Common/StringUtil.h" 19 #include "Common/Swap.h" 20 #include "Core/IOS/ES/Formats.h" 21 #include "DiscIO/Enums.h" 22 23 namespace DiscIO 24 { 25 class BlobReader; 26 enum class BlobType; 27 class FileSystem; 28 class VolumeDisc; 29 class VolumeWAD; 30 31 struct Partition final 32 { 33 constexpr Partition() = default; Partitionfinal34 constexpr explicit Partition(u64 offset_) : offset(offset_) {} 35 constexpr bool operator==(const Partition& other) const { return offset == other.offset; } 36 constexpr bool operator!=(const Partition& other) const { return !(*this == other); } 37 constexpr bool operator<(const Partition& other) const { return offset < other.offset; } 38 constexpr bool operator>(const Partition& other) const { return other < *this; } 39 constexpr bool operator<=(const Partition& other) const { return !(*this < other); } 40 constexpr bool operator>=(const Partition& other) const { return !(*this > other); } 41 u64 offset{std::numeric_limits<u64>::max()}; 42 }; 43 44 constexpr Partition PARTITION_NONE(std::numeric_limits<u64>::max() - 1); 45 46 class Volume 47 { 48 public: Volume()49 Volume() {} ~Volume()50 virtual ~Volume() {} 51 virtual bool Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const = 0; 52 template <typename T> ReadSwapped(u64 offset,const Partition & partition)53 std::optional<T> ReadSwapped(u64 offset, const Partition& partition) const 54 { 55 T temp; 56 if (!Read(offset, sizeof(T), reinterpret_cast<u8*>(&temp), partition)) 57 return std::nullopt; 58 return Common::FromBigEndian(temp); 59 } ReadSwappedAndShifted(u64 offset,const Partition & partition)60 std::optional<u64> ReadSwappedAndShifted(u64 offset, const Partition& partition) const 61 { 62 const std::optional<u32> temp = ReadSwapped<u32>(offset, partition); 63 if (!temp) 64 return std::nullopt; 65 return static_cast<u64>(*temp) << GetOffsetShift(); 66 } 67 IsEncryptedAndHashed()68 virtual bool IsEncryptedAndHashed() const { return false; } GetPartitions()69 virtual std::vector<Partition> GetPartitions() const { return {}; } GetGamePartition()70 virtual Partition GetGamePartition() const { return PARTITION_NONE; } GetPartitionType(const Partition & partition)71 virtual std::optional<u32> GetPartitionType(const Partition& partition) const 72 { 73 return std::nullopt; 74 } GetTitleID()75 std::optional<u64> GetTitleID() const { return GetTitleID(GetGamePartition()); } GetTitleID(const Partition & partition)76 virtual std::optional<u64> GetTitleID(const Partition& partition) const { return std::nullopt; } GetTicket(const Partition & partition)77 virtual const IOS::ES::TicketReader& GetTicket(const Partition& partition) const 78 { 79 return INVALID_TICKET; 80 } GetTMD(const Partition & partition)81 virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; } GetCertificateChain(const Partition & partition)82 virtual const std::vector<u8>& GetCertificateChain(const Partition& partition) const 83 { 84 return INVALID_CERT_CHAIN; 85 } GetContent(u16 index)86 virtual std::vector<u8> GetContent(u16 index) const { return {}; } GetContentOffsets()87 virtual std::vector<u64> GetContentOffsets() const { return {}; } CheckContentIntegrity(const IOS::ES::Content & content,const std::vector<u8> & encrypted_data,const IOS::ES::TicketReader & ticket)88 virtual bool CheckContentIntegrity(const IOS::ES::Content& content, 89 const std::vector<u8>& encrypted_data, 90 const IOS::ES::TicketReader& ticket) const 91 { 92 return false; 93 } CheckContentIntegrity(const IOS::ES::Content & content,u64 content_offset,const IOS::ES::TicketReader & ticket)94 virtual bool CheckContentIntegrity(const IOS::ES::Content& content, u64 content_offset, 95 const IOS::ES::TicketReader& ticket) const 96 { 97 return false; 98 } GetTicketWithFixedCommonKey()99 virtual IOS::ES::TicketReader GetTicketWithFixedCommonKey() const { return {}; } 100 // Returns a non-owning pointer. Returns nullptr if the file system couldn't be read. 101 virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0; PartitionOffsetToRawOffset(u64 offset,const Partition & partition)102 virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const 103 { 104 return offset; 105 } 106 virtual std::string GetGameID(const Partition& partition = PARTITION_NONE) const = 0; 107 virtual std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const = 0; 108 virtual std::string GetMakerID(const Partition& partition = PARTITION_NONE) const = 0; 109 virtual std::optional<u16> GetRevision(const Partition& partition = PARTITION_NONE) const = 0; 110 virtual std::string GetInternalName(const Partition& partition = PARTITION_NONE) const = 0; GetShortNames()111 virtual std::map<Language, std::string> GetShortNames() const { return {}; } GetLongNames()112 virtual std::map<Language, std::string> GetLongNames() const { return {}; } GetShortMakers()113 virtual std::map<Language, std::string> GetShortMakers() const { return {}; } GetLongMakers()114 virtual std::map<Language, std::string> GetLongMakers() const { return {}; } GetDescriptions()115 virtual std::map<Language, std::string> GetDescriptions() const { return {}; } 116 virtual std::vector<u32> GetBanner(u32* width, u32* height) const = 0; GetApploaderDate()117 std::string GetApploaderDate() const { return GetApploaderDate(GetGamePartition()); } 118 virtual std::string GetApploaderDate(const Partition& partition) const = 0; 119 // 0 is the first disc, 1 is the second disc 120 virtual std::optional<u8> GetDiscNumber(const Partition& partition = PARTITION_NONE) const 121 { 122 return 0; 123 } 124 virtual Platform GetVolumeType() const = 0; 125 virtual bool IsDatelDisc() const = 0; 126 virtual bool IsNKit() const = 0; SupportsIntegrityCheck()127 virtual bool SupportsIntegrityCheck() const { return false; } CheckH3TableIntegrity(const Partition & partition)128 virtual bool CheckH3TableIntegrity(const Partition& partition) const { return false; } CheckBlockIntegrity(u64 block_index,const std::vector<u8> & encrypted_data,const Partition & partition)129 virtual bool CheckBlockIntegrity(u64 block_index, const std::vector<u8>& encrypted_data, 130 const Partition& partition) const 131 { 132 return false; 133 } CheckBlockIntegrity(u64 block_index,const Partition & partition)134 virtual bool CheckBlockIntegrity(u64 block_index, const Partition& partition) const 135 { 136 return false; 137 } 138 virtual Region GetRegion() const = 0; 139 virtual Country GetCountry(const Partition& partition = PARTITION_NONE) const = 0; 140 virtual BlobType GetBlobType() const = 0; 141 // Size of virtual disc (may be inaccurate depending on the blob type) 142 virtual u64 GetSize() const = 0; 143 virtual bool IsSizeAccurate() const = 0; 144 // Size on disc (compressed size) 145 virtual u64 GetRawSize() const = 0; 146 virtual const BlobReader& GetBlobReader() const = 0; 147 148 // This hash is intended to be (but is not guaranteed to be): 149 // 1. Identical for discs with no differences that affect netplay/TAS sync 150 // 2. Different for discs with differences that affect netplay/TAS sync 151 // 3. Much faster than hashing the entire disc 152 // The way the hash is calculated may change with updates to Dolphin. 153 virtual std::array<u8, 20> GetSyncHash() const = 0; 154 155 protected: 156 template <u32 N> DecodeString(const char (& data)[N])157 std::string DecodeString(const char (&data)[N]) const 158 { 159 // strnlen to trim NULLs 160 std::string string(data, strnlen(data, sizeof(data))); 161 162 if (GetRegion() == Region::NTSC_J) 163 return SHIFTJISToUTF8(string); 164 else 165 return CP1252ToUTF8(string); 166 } 167 168 void ReadAndAddToSyncHash(mbedtls_sha1_context* context, u64 offset, u64 length, 169 const Partition& partition) const; 170 void AddTMDToSyncHash(mbedtls_sha1_context* context, const Partition& partition) const; 171 GetOffsetShift()172 virtual u32 GetOffsetShift() const { return 0; } 173 static std::map<Language, std::string> ReadWiiNames(const std::vector<char16_t>& data); 174 175 static const size_t NUMBER_OF_LANGUAGES = 10; 176 static const size_t NAME_CHARS_LENGTH = 42; 177 static const size_t NAME_BYTES_LENGTH = NAME_CHARS_LENGTH * sizeof(char16_t); 178 static const size_t NAMES_TOTAL_CHARS = NAME_CHARS_LENGTH * NUMBER_OF_LANGUAGES; 179 static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES; 180 181 static const IOS::ES::TicketReader INVALID_TICKET; 182 static const IOS::ES::TMDReader INVALID_TMD; 183 static const std::vector<u8> INVALID_CERT_CHAIN; 184 }; 185 186 std::unique_ptr<VolumeDisc> CreateDisc(const std::string& path); 187 std::unique_ptr<VolumeWAD> CreateWAD(const std::string& path); 188 std::unique_ptr<Volume> CreateVolume(const std::string& path); 189 190 } // namespace DiscIO 191