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