// Copyright 2008 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include #include "Common/CommonTypes.h" #include "Common/Crypto/SHA1.h" #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/IOS/ES/Formats.h" #include "DiscIO/Enums.h" namespace DiscIO { class BlobReader; enum class BlobType; enum class DataSizeType; class FileSystem; class VolumeDisc; class VolumeWAD; struct Partition final { constexpr Partition() = default; constexpr explicit Partition(u64 offset_) : offset(offset_) {} constexpr bool operator==(const Partition& other) const { return offset == other.offset; } constexpr bool operator!=(const Partition& other) const { return !(*this == other); } constexpr bool operator<(const Partition& other) const { return offset < other.offset; } constexpr bool operator>(const Partition& other) const { return other < *this; } constexpr bool operator<=(const Partition& other) const { return !(*this < other); } constexpr bool operator>=(const Partition& other) const { return !(*this > other); } u64 offset{std::numeric_limits::max()}; }; constexpr Partition PARTITION_NONE(std::numeric_limits::max() - 1); class Volume { public: Volume() {} virtual ~Volume() {} virtual bool Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const = 0; template std::optional ReadSwapped(u64 offset, const Partition& partition) const { T temp; if (!Read(offset, sizeof(T), reinterpret_cast(&temp), partition)) return std::nullopt; return Common::FromBigEndian(temp); } std::optional ReadSwappedAndShifted(u64 offset, const Partition& partition) const { const std::optional temp = ReadSwapped(offset, partition); if (!temp) return std::nullopt; return static_cast(*temp) << GetOffsetShift(); } virtual bool HasWiiHashes() const { return false; } virtual bool HasWiiEncryption() const { return false; } virtual std::vector GetPartitions() const { return {}; } virtual Partition GetGamePartition() const { return PARTITION_NONE; } virtual std::optional GetPartitionType(const Partition& partition) const { return std::nullopt; } std::optional GetTitleID() const { return GetTitleID(GetGamePartition()); } virtual std::optional GetTitleID(const Partition& partition) const { return std::nullopt; } virtual const IOS::ES::TicketReader& GetTicket(const Partition& partition) const { return INVALID_TICKET; } virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; } virtual const std::vector& GetCertificateChain(const Partition& partition) const { return INVALID_CERT_CHAIN; } virtual std::vector GetContent(u16 index) const { return {}; } virtual std::vector GetContentOffsets() const { return {}; } virtual bool CheckContentIntegrity(const IOS::ES::Content& content, const std::vector& encrypted_data, const IOS::ES::TicketReader& ticket) const { return false; } virtual bool CheckContentIntegrity(const IOS::ES::Content& content, u64 content_offset, const IOS::ES::TicketReader& ticket) const { return false; } virtual IOS::ES::TicketReader GetTicketWithFixedCommonKey() const { return {}; } // Returns a non-owning pointer. Returns nullptr if the file system couldn't be read. virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0; virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const { return offset; } virtual std::string GetGameID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetMakerID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::optional GetRevision(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetInternalName(const Partition& partition = PARTITION_NONE) const = 0; virtual std::map GetShortNames() const { return {}; } virtual std::map GetLongNames() const { return {}; } virtual std::map GetShortMakers() const { return {}; } virtual std::map GetLongMakers() const { return {}; } virtual std::map GetDescriptions() const { return {}; } virtual std::vector GetBanner(u32* width, u32* height) const = 0; std::string GetApploaderDate() const { return GetApploaderDate(GetGamePartition()); } virtual std::string GetApploaderDate(const Partition& partition) const = 0; // 0 is the first disc, 1 is the second disc virtual std::optional GetDiscNumber(const Partition& partition = PARTITION_NONE) const { return 0; } virtual Platform GetVolumeType() const = 0; virtual bool IsDatelDisc() const = 0; virtual bool IsNKit() const = 0; virtual bool CheckH3TableIntegrity(const Partition& partition) const { return false; } virtual bool CheckBlockIntegrity(u64 block_index, const u8* encrypted_data, const Partition& partition) const { return false; } virtual bool CheckBlockIntegrity(u64 block_index, const Partition& partition) const { return false; } virtual Region GetRegion() const = 0; virtual Country GetCountry(const Partition& partition = PARTITION_NONE) const = 0; virtual BlobType GetBlobType() const = 0; // Size of virtual disc (may be inaccurate depending on the blob type) virtual u64 GetDataSize() const = 0; virtual DataSizeType GetDataSizeType() const = 0; // Size on disc (compressed size) virtual u64 GetRawSize() const = 0; virtual const BlobReader& GetBlobReader() const = 0; // This hash is intended to be (but is not guaranteed to be): // 1. Identical for discs with no differences that affect netplay/TAS sync // 2. Different for discs with differences that affect netplay/TAS sync // 3. Much faster than hashing the entire disc // The way the hash is calculated may change with updates to Dolphin. virtual std::array GetSyncHash() const = 0; protected: template std::string DecodeString(const char (&data)[N]) const { // strnlen to trim NULLs std::string string(data, strnlen(data, sizeof(data))); if (GetRegion() == Region::NTSC_J) return SHIFTJISToUTF8(string); else return CP1252ToUTF8(string); } void ReadAndAddToSyncHash(Common::SHA1::Context* context, u64 offset, u64 length, const Partition& partition) const; void AddTMDToSyncHash(Common::SHA1::Context* context, const Partition& partition) const; virtual u32 GetOffsetShift() const { return 0; } static std::map ReadWiiNames(const std::vector& data); static const size_t NUMBER_OF_LANGUAGES = 10; static const size_t NAME_CHARS_LENGTH = 42; static const size_t NAME_BYTES_LENGTH = NAME_CHARS_LENGTH * sizeof(char16_t); static const size_t NAMES_TOTAL_CHARS = NAME_CHARS_LENGTH * NUMBER_OF_LANGUAGES; static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES; static const IOS::ES::TicketReader INVALID_TICKET; static const IOS::ES::TMDReader INVALID_TMD; static const std::vector INVALID_CERT_CHAIN; }; std::unique_ptr CreateDisc(std::unique_ptr reader); std::unique_ptr CreateDisc(const std::string& path); std::unique_ptr CreateWAD(std::unique_ptr reader); std::unique_ptr CreateWAD(const std::string& path); std::unique_ptr CreateVolume(std::unique_ptr reader); std::unique_ptr CreateVolume(const std::string& path); } // namespace DiscIO