2015-05-23 22:55:12 -06:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2008-12-07 21:46:09 -07:00
|
|
|
|
2014-02-10 11:54:46 -07:00
|
|
|
#pragma once
|
2008-12-07 21:46:09 -07:00
|
|
|
|
2015-12-08 15:49:48 -07:00
|
|
|
#include <cstring>
|
2015-06-13 04:51:24 -06:00
|
|
|
#include <limits>
|
2015-04-09 09:44:53 -06:00
|
|
|
#include <map>
|
2017-05-19 10:33:21 -06:00
|
|
|
#include <memory>
|
2017-06-03 13:29:08 -06:00
|
|
|
#include <optional>
|
2008-07-12 11:40:22 -06:00
|
|
|
#include <string>
|
2008-09-17 21:18:19 -06:00
|
|
|
#include <vector>
|
2008-12-07 21:46:09 -07:00
|
|
|
|
2020-06-07 14:58:03 -06:00
|
|
|
#include <mbedtls/sha1.h>
|
|
|
|
|
2014-09-07 19:06:58 -06:00
|
|
|
#include "Common/CommonTypes.h"
|
2015-04-10 14:10:49 -06:00
|
|
|
#include "Common/StringUtil.h"
|
2017-03-03 12:43:52 -07:00
|
|
|
#include "Common/Swap.h"
|
2017-02-11 00:57:47 -07:00
|
|
|
#include "Core/IOS/ES/Formats.h"
|
2016-07-06 12:33:05 -06:00
|
|
|
#include "DiscIO/Enums.h"
|
2008-12-07 21:46:09 -07:00
|
|
|
|
2008-07-12 11:40:22 -06:00
|
|
|
namespace DiscIO
|
|
|
|
{
|
2020-06-07 06:11:00 -06:00
|
|
|
class BlobReader;
|
2016-07-06 12:33:05 -06:00
|
|
|
enum class BlobType;
|
2017-08-02 10:16:56 -06:00
|
|
|
class FileSystem;
|
2020-06-04 12:33:52 -06:00
|
|
|
class VolumeDisc;
|
2019-07-14 07:49:42 -06:00
|
|
|
class VolumeWAD;
|
2016-07-06 12:33:05 -06:00
|
|
|
|
2015-06-13 04:51:24 -06:00
|
|
|
struct Partition final
|
|
|
|
{
|
2019-08-02 15:53:18 -06:00
|
|
|
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<u64>::max()};
|
2015-06-13 04:51:24 -06:00
|
|
|
};
|
|
|
|
|
2019-08-02 15:53:18 -06:00
|
|
|
constexpr Partition PARTITION_NONE(std::numeric_limits<u64>::max() - 1);
|
2015-06-13 04:51:24 -06:00
|
|
|
|
2017-06-06 03:49:01 -06:00
|
|
|
class Volume
|
2008-07-12 11:40:22 -06:00
|
|
|
{
|
2009-08-31 16:42:10 -06:00
|
|
|
public:
|
2017-06-06 03:49:01 -06:00
|
|
|
Volume() {}
|
|
|
|
virtual ~Volume() {}
|
2018-05-30 00:37:13 -06:00
|
|
|
virtual bool Read(u64 offset, u64 length, u8* buffer, const Partition& partition) const = 0;
|
2015-10-03 05:24:13 -06:00
|
|
|
template <typename T>
|
2017-06-04 02:33:14 -06:00
|
|
|
std::optional<T> ReadSwapped(u64 offset, const Partition& partition) const
|
2015-04-05 02:09:48 -06:00
|
|
|
{
|
2015-10-03 05:24:13 -06:00
|
|
|
T temp;
|
2015-06-13 04:51:24 -06:00
|
|
|
if (!Read(offset, sizeof(T), reinterpret_cast<u8*>(&temp), partition))
|
2019-12-27 11:17:56 -07:00
|
|
|
return std::nullopt;
|
2017-06-04 02:33:14 -06:00
|
|
|
return Common::FromBigEndian(temp);
|
2015-04-05 02:09:48 -06:00
|
|
|
}
|
2017-06-07 03:49:34 -06:00
|
|
|
std::optional<u64> ReadSwappedAndShifted(u64 offset, const Partition& partition) const
|
|
|
|
{
|
|
|
|
const std::optional<u32> temp = ReadSwapped<u32>(offset, partition);
|
2020-07-31 18:28:21 -06:00
|
|
|
if (!temp)
|
|
|
|
return std::nullopt;
|
|
|
|
return static_cast<u64>(*temp) << GetOffsetShift();
|
2017-06-07 03:49:34 -06:00
|
|
|
}
|
|
|
|
|
2018-05-22 14:39:52 -06:00
|
|
|
virtual bool IsEncryptedAndHashed() const { return false; }
|
2017-06-03 10:14:22 -06:00
|
|
|
virtual std::vector<Partition> GetPartitions() const { return {}; }
|
2015-06-13 04:51:24 -06:00
|
|
|
virtual Partition GetGamePartition() const { return PARTITION_NONE; }
|
2020-07-31 18:28:21 -06:00
|
|
|
virtual std::optional<u32> GetPartitionType(const Partition& partition) const
|
|
|
|
{
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2018-09-30 09:45:18 -06:00
|
|
|
std::optional<u64> GetTitleID() const { return GetTitleID(GetGamePartition()); }
|
2020-07-31 18:28:21 -06:00
|
|
|
virtual std::optional<u64> GetTitleID(const Partition& partition) const { return std::nullopt; }
|
2017-05-20 10:33:36 -06:00
|
|
|
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; }
|
2019-03-21 16:04:44 -06:00
|
|
|
virtual const std::vector<u8>& GetCertificateChain(const Partition& partition) const
|
|
|
|
{
|
|
|
|
return INVALID_CERT_CHAIN;
|
|
|
|
}
|
2019-07-14 10:00:14 -06:00
|
|
|
virtual std::vector<u8> GetContent(u16 index) const { return {}; }
|
2019-03-30 10:42:31 -06:00
|
|
|
virtual std::vector<u64> GetContentOffsets() const { return {}; }
|
2019-08-05 05:58:27 -06:00
|
|
|
virtual bool CheckContentIntegrity(const IOS::ES::Content& content,
|
|
|
|
const std::vector<u8>& encrypted_data,
|
|
|
|
const IOS::ES::TicketReader& ticket) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-14 07:01:07 -06:00
|
|
|
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 {}; }
|
2017-08-02 10:16:56 -06:00
|
|
|
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
|
|
|
|
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
|
2018-05-22 14:39:52 -06:00
|
|
|
virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
|
|
|
|
{
|
|
|
|
return offset;
|
|
|
|
}
|
2018-09-12 04:54:36 -06:00
|
|
|
virtual std::string GetGameID(const Partition& partition = PARTITION_NONE) const = 0;
|
2019-02-23 09:49:06 -07:00
|
|
|
virtual std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const = 0;
|
2018-09-12 04:54:36 -06:00
|
|
|
virtual std::string GetMakerID(const Partition& partition = PARTITION_NONE) const = 0;
|
|
|
|
virtual std::optional<u16> GetRevision(const Partition& partition = PARTITION_NONE) const = 0;
|
|
|
|
virtual std::string GetInternalName(const Partition& partition = PARTITION_NONE) const = 0;
|
2017-06-03 10:14:22 -06:00
|
|
|
virtual std::map<Language, std::string> GetShortNames() const { return {}; }
|
|
|
|
virtual std::map<Language, std::string> GetLongNames() const { return {}; }
|
|
|
|
virtual std::map<Language, std::string> GetShortMakers() const { return {}; }
|
|
|
|
virtual std::map<Language, std::string> GetLongMakers() const { return {}; }
|
|
|
|
virtual std::map<Language, std::string> GetDescriptions() const { return {}; }
|
2018-03-10 14:41:49 -07:00
|
|
|
virtual std::vector<u32> GetBanner(u32* width, u32* height) const = 0;
|
2015-06-13 04:51:24 -06:00
|
|
|
std::string GetApploaderDate() const { return GetApploaderDate(GetGamePartition()); }
|
|
|
|
virtual std::string GetApploaderDate(const Partition& partition) const = 0;
|
2015-05-29 13:14:02 -06:00
|
|
|
// 0 is the first disc, 1 is the second disc
|
2018-09-12 04:54:36 -06:00
|
|
|
virtual std::optional<u8> GetDiscNumber(const Partition& partition = PARTITION_NONE) const
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2016-07-06 12:33:05 -06:00
|
|
|
virtual Platform GetVolumeType() const = 0;
|
2020-07-04 06:51:13 -06:00
|
|
|
virtual bool IsDatelDisc() const = 0;
|
2020-06-15 05:16:01 -06:00
|
|
|
virtual bool IsNKit() const = 0;
|
2012-05-04 04:49:10 -06:00
|
|
|
virtual bool SupportsIntegrityCheck() const { return false; }
|
2019-03-26 10:22:18 -06:00
|
|
|
virtual bool CheckH3TableIntegrity(const Partition& partition) const { return false; }
|
2021-03-07 05:48:51 -07:00
|
|
|
virtual bool CheckBlockIntegrity(u64 block_index, const u8* encrypted_data,
|
2019-08-05 05:58:27 -06:00
|
|
|
const Partition& partition) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-26 10:22:18 -06:00
|
|
|
virtual bool CheckBlockIntegrity(u64 block_index, const Partition& partition) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-12-23 10:41:21 -07:00
|
|
|
virtual Region GetRegion() const = 0;
|
2018-09-12 04:54:36 -06:00
|
|
|
virtual Country GetCountry(const Partition& partition = PARTITION_NONE) const = 0;
|
2015-09-27 06:01:12 -06:00
|
|
|
virtual BlobType GetBlobType() const = 0;
|
2015-06-13 04:51:24 -06:00
|
|
|
// Size of virtual disc (may be inaccurate depending on the blob type)
|
2009-08-31 16:42:10 -06:00
|
|
|
virtual u64 GetSize() const = 0;
|
2019-03-21 15:20:23 -06:00
|
|
|
virtual bool IsSizeAccurate() const = 0;
|
2013-04-09 11:58:56 -06:00
|
|
|
// Size on disc (compressed size)
|
|
|
|
virtual u64 GetRawSize() const = 0;
|
2020-06-07 06:11:00 -06:00
|
|
|
virtual const BlobReader& GetBlobReader() const = 0;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2020-06-07 14:58:03 -06:00
|
|
|
// 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<u8, 20> GetSyncHash() const = 0;
|
|
|
|
|
2015-04-10 14:10:49 -06:00
|
|
|
protected:
|
|
|
|
template <u32 N>
|
|
|
|
std::string DecodeString(const char (&data)[N]) const
|
|
|
|
{
|
|
|
|
// strnlen to trim NULLs
|
|
|
|
std::string string(data, strnlen(data, sizeof(data)));
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2016-12-23 10:41:21 -07:00
|
|
|
if (GetRegion() == Region::NTSC_J)
|
2015-04-10 14:10:49 -06:00
|
|
|
return SHIFTJISToUTF8(string);
|
|
|
|
else
|
|
|
|
return CP1252ToUTF8(string);
|
|
|
|
}
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2020-06-07 14:58:03 -06:00
|
|
|
void ReadAndAddToSyncHash(mbedtls_sha1_context* context, u64 offset, u64 length,
|
|
|
|
const Partition& partition) const;
|
|
|
|
void AddTMDToSyncHash(mbedtls_sha1_context* context, const Partition& partition) const;
|
|
|
|
|
2017-06-07 03:49:34 -06:00
|
|
|
virtual u32 GetOffsetShift() const { return 0; }
|
2017-11-02 14:05:37 -06:00
|
|
|
static std::map<Language, std::string> ReadWiiNames(const std::vector<char16_t>& data);
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2015-04-10 15:18:41 -06:00
|
|
|
static const size_t NUMBER_OF_LANGUAGES = 10;
|
2017-11-02 14:05:37 -06:00
|
|
|
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;
|
2015-04-10 15:18:41 -06:00
|
|
|
static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES;
|
2017-05-20 10:33:36 -06:00
|
|
|
|
|
|
|
static const IOS::ES::TicketReader INVALID_TICKET;
|
|
|
|
static const IOS::ES::TMDReader INVALID_TMD;
|
2019-03-21 16:04:44 -06:00
|
|
|
static const std::vector<u8> INVALID_CERT_CHAIN;
|
2008-07-12 11:40:22 -06:00
|
|
|
};
|
2009-07-03 16:34:51 -06:00
|
|
|
|
2021-09-21 21:43:05 -06:00
|
|
|
std::unique_ptr<VolumeDisc> CreateDisc(std::unique_ptr<BlobReader> reader);
|
2019-07-14 07:49:42 -06:00
|
|
|
std::unique_ptr<VolumeDisc> CreateDisc(const std::string& path);
|
2021-09-21 21:43:05 -06:00
|
|
|
std::unique_ptr<VolumeWAD> CreateWAD(std::unique_ptr<BlobReader> reader);
|
2019-07-14 07:49:42 -06:00
|
|
|
std::unique_ptr<VolumeWAD> CreateWAD(const std::string& path);
|
2021-09-21 21:43:05 -06:00
|
|
|
std::unique_ptr<Volume> CreateVolume(std::unique_ptr<BlobReader> reader);
|
2019-07-14 07:49:42 -06:00
|
|
|
std::unique_ptr<Volume> CreateVolume(const std::string& path);
|
2017-05-19 10:33:21 -06:00
|
|
|
|
2019-03-21 16:04:44 -06:00
|
|
|
} // namespace DiscIO
|