mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7922 from JosJuice/verify-disc
Add a Verify tab to game properties
This commit is contained in:
@@ -140,6 +140,27 @@ public:
|
||||
|
||||
bool CreateTitleDirectories(u64 title_id, u16 group_id) const;
|
||||
|
||||
enum class VerifyContainerType
|
||||
{
|
||||
TMD,
|
||||
Ticket,
|
||||
Device,
|
||||
};
|
||||
enum class VerifyMode
|
||||
{
|
||||
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
|
||||
DoNotUpdateCertStore,
|
||||
UpdateCertStore,
|
||||
};
|
||||
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
|
||||
// The caller is responsible for using IOSC_DeleteObject.
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::SignedBlobReader& signed_blob,
|
||||
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::CertReader& certificate,
|
||||
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -308,29 +329,9 @@ private:
|
||||
ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
|
||||
const IOS::ES::TMDReader& tmd) const;
|
||||
|
||||
enum class VerifyContainerType
|
||||
{
|
||||
TMD,
|
||||
Ticket,
|
||||
Device,
|
||||
};
|
||||
enum class VerifyMode
|
||||
{
|
||||
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
|
||||
DoNotUpdateCertStore,
|
||||
UpdateCertStore,
|
||||
};
|
||||
bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const;
|
||||
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
|
||||
ReturnCode WriteNewCertToStore(const IOS::ES::CertReader& cert);
|
||||
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
|
||||
// The caller is responsible for using IOSC_DeleteObject.
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::SignedBlobReader& signed_blob,
|
||||
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
|
||||
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
|
||||
const IOS::ES::CertReader& certificate,
|
||||
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);
|
||||
|
||||
// Start a title import.
|
||||
bool InitImport(const IOS::ES::TMDReader& tmd);
|
||||
|
||||
@@ -441,6 +441,11 @@ u64 TicketReader::GetTitleId() const
|
||||
return Common::swap64(m_bytes.data() + offsetof(Ticket, title_id));
|
||||
}
|
||||
|
||||
u8 TicketReader::GetCommonKeyIndex() const
|
||||
{
|
||||
return m_bytes[offsetof(Ticket, common_key_index)];
|
||||
}
|
||||
|
||||
std::array<u8, 16> TicketReader::GetTitleKey(const HLE::IOSC& iosc) const
|
||||
{
|
||||
u8 iv[16] = {};
|
||||
|
||||
@@ -240,6 +240,7 @@ public:
|
||||
|
||||
u32 GetDeviceId() const;
|
||||
u64 GetTitleId() const;
|
||||
u8 GetCommonKeyIndex() const;
|
||||
// Get the decrypted title key.
|
||||
std::array<u8, 16> GetTitleKey(const HLE::IOSC& iosc) const;
|
||||
// Same as the above version, but guesses the console type depending on the issuer
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
virtual BlobType GetBlobType() const = 0;
|
||||
virtual u64 GetRawSize() const = 0;
|
||||
virtual u64 GetDataSize() const = 0;
|
||||
virtual bool IsDataSizeAccurate() const = 0;
|
||||
|
||||
// NOT thread-safe - can't call this from multiple threads.
|
||||
virtual bool Read(u64 offset, u64 size, u8* out_ptr) = 0;
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
// The CISO format does not save the original file size.
|
||||
// This function returns an upper bound.
|
||||
u64 GetDataSize() const override;
|
||||
bool IsDataSizeAccurate() const override { return false; }
|
||||
|
||||
u64 GetRawSize() const override;
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
|
||||
@@ -16,6 +16,7 @@ add_library(discio
|
||||
Volume.cpp
|
||||
VolumeFileBlobReader.cpp
|
||||
VolumeGC.cpp
|
||||
VolumeVerifier.cpp
|
||||
VolumeWad.cpp
|
||||
VolumeWii.cpp
|
||||
WiiSaveBanner.cpp
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/CompressedBlob.h"
|
||||
#include "DiscIO/DiscScrubber.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
@@ -181,9 +182,11 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi
|
||||
}
|
||||
|
||||
DiscScrubber disc_scrubber;
|
||||
std::unique_ptr<Volume> volume;
|
||||
if (sub_type == 1)
|
||||
{
|
||||
if (!disc_scrubber.SetupScrub(infile_path, block_size))
|
||||
volume = CreateVolumeFromFilename(infile_path);
|
||||
if (!volume || !disc_scrubber.SetupScrub(volume.get(), block_size))
|
||||
{
|
||||
PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.",
|
||||
infile_path.c_str());
|
||||
|
||||
@@ -49,8 +49,9 @@ public:
|
||||
~CompressedBlobReader();
|
||||
const CompressedBlobHeader& GetHeader() const { return m_header; }
|
||||
BlobType GetBlobType() const override { return BlobType::GCZ; }
|
||||
u64 GetDataSize() const override { return m_header.data_size; }
|
||||
u64 GetRawSize() const override { return m_file_size; }
|
||||
u64 GetDataSize() const override { return m_header.data_size; }
|
||||
bool IsDataSizeAccurate() const override { return true; }
|
||||
u64 GetBlockCompressedSize(u64 block_num) const;
|
||||
bool GetBlock(u64 block_num, u8* out_ptr) override;
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ public:
|
||||
BlobType GetBlobType() const override;
|
||||
u64 GetRawSize() const override;
|
||||
u64 GetDataSize() const override;
|
||||
bool IsDataSizeAccurate() const override { return true; }
|
||||
|
||||
private:
|
||||
struct PartitionWithType
|
||||
|
||||
@@ -19,16 +19,21 @@
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
std::string DirectoryNameForPartitionType(u32 partition_type)
|
||||
std::string NameForPartitionType(u32 partition_type, bool include_prefix)
|
||||
{
|
||||
switch (partition_type)
|
||||
{
|
||||
case 0:
|
||||
case PARTITION_DATA:
|
||||
return "DATA";
|
||||
case 1:
|
||||
case PARTITION_UPDATE:
|
||||
return "UPDATE";
|
||||
case 2:
|
||||
case PARTITION_CHANNEL:
|
||||
return "CHANNEL";
|
||||
case PARTITION_INSTALL:
|
||||
// wit doesn't recognize the name "INSTALL", so we can't use it when naming partition folders
|
||||
if (!include_prefix)
|
||||
return "INSTALL";
|
||||
// [[fallthrough]]
|
||||
default:
|
||||
const std::string type_as_game_id{static_cast<char>((partition_type >> 24) & 0xFF),
|
||||
static_cast<char>((partition_type >> 16) & 0xFF),
|
||||
@@ -37,10 +42,10 @@ std::string DirectoryNameForPartitionType(u32 partition_type)
|
||||
if (std::all_of(type_as_game_id.cbegin(), type_as_game_id.cend(),
|
||||
[](char c) { return std::isalnum(c, std::locale::classic()); }))
|
||||
{
|
||||
return "P-" + type_as_game_id;
|
||||
return include_prefix ? "P-" + type_as_game_id : type_as_game_id;
|
||||
}
|
||||
|
||||
return StringFromFormat("P%u", partition_type);
|
||||
return StringFromFormat(include_prefix ? "P%u" : "%u", partition_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,12 @@ class FileInfo;
|
||||
struct Partition;
|
||||
class Volume;
|
||||
|
||||
std::string DirectoryNameForPartitionType(u32 partition_type);
|
||||
constexpr u32 PARTITION_DATA = 0;
|
||||
constexpr u32 PARTITION_UPDATE = 1;
|
||||
constexpr u32 PARTITION_CHANNEL = 2; // Mario Kart Wii, Wii Fit, Wii Fit Plus, Rabbids Go Home
|
||||
constexpr u32 PARTITION_INSTALL = 3; // Dragon Quest X only
|
||||
|
||||
std::string NameForPartitionType(u32 partition_type, bool include_prefix);
|
||||
|
||||
u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
|
||||
u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0);
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<ClCompile Include="Volume.cpp" />
|
||||
<ClCompile Include="VolumeFileBlobReader.cpp" />
|
||||
<ClCompile Include="VolumeGC.cpp" />
|
||||
<ClCompile Include="VolumeVerifier.cpp" />
|
||||
<ClCompile Include="VolumeWad.cpp" />
|
||||
<ClCompile Include="VolumeWii.cpp" />
|
||||
<ClCompile Include="WbfsBlob.cpp" />
|
||||
@@ -75,6 +76,7 @@
|
||||
<ClInclude Include="Volume.h" />
|
||||
<ClInclude Include="VolumeFileBlobReader.h" />
|
||||
<ClInclude Include="VolumeGC.h" />
|
||||
<ClInclude Include="VolumeVerifier.h" />
|
||||
<ClInclude Include="VolumeWad.h" />
|
||||
<ClInclude Include="VolumeWii.h" />
|
||||
<ClInclude Include="WbfsBlob.h" />
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<ClCompile Include="WiiSaveBanner.cpp">
|
||||
<Filter>NAND</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VolumeVerifier.cpp">
|
||||
<Filter>Volume</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DiscScrubber.h">
|
||||
@@ -149,6 +152,9 @@
|
||||
<ClInclude Include="WiiSaveBanner.h">
|
||||
<Filter>NAND</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VolumeVerifier.h">
|
||||
<Filter>Volume</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
||||
@@ -28,9 +28,11 @@ constexpr size_t CLUSTER_SIZE = 0x8000;
|
||||
DiscScrubber::DiscScrubber() = default;
|
||||
DiscScrubber::~DiscScrubber() = default;
|
||||
|
||||
bool DiscScrubber::SetupScrub(const std::string& filename, int block_size)
|
||||
bool DiscScrubber::SetupScrub(const Volume* disc, int block_size)
|
||||
{
|
||||
m_filename = filename;
|
||||
if (!disc)
|
||||
return false;
|
||||
m_disc = disc;
|
||||
m_block_size = block_size;
|
||||
|
||||
if (CLUSTER_SIZE % m_block_size != 0)
|
||||
@@ -40,20 +42,13 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_disc = CreateVolumeFromFilename(filename);
|
||||
if (!m_disc)
|
||||
return false;
|
||||
|
||||
m_file_size = m_disc->GetSize();
|
||||
|
||||
const size_t num_clusters = static_cast<size_t>(m_file_size / CLUSTER_SIZE);
|
||||
|
||||
// Warn if not DVD5 or DVD9 size
|
||||
if (num_clusters != 0x23048 && num_clusters != 0x46090)
|
||||
{
|
||||
WARN_LOG(DISCIO, "%s is not a standard sized Wii disc! (%zx blocks)", filename.c_str(),
|
||||
num_clusters);
|
||||
}
|
||||
WARN_LOG(DISCIO, "Not a standard sized Wii disc! (%zx blocks)", num_clusters);
|
||||
|
||||
// Table of free blocks
|
||||
m_free_table.resize(num_clusters, 1);
|
||||
@@ -61,8 +56,6 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size)
|
||||
// Fill out table of free blocks
|
||||
const bool success = ParseDisc();
|
||||
|
||||
// Done with it; need it closed for the next part
|
||||
m_disc.reset();
|
||||
m_block_count = 0;
|
||||
|
||||
m_is_scrubbing = success;
|
||||
@@ -72,10 +65,9 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size)
|
||||
size_t DiscScrubber::GetNextBlock(File::IOFile& in, u8* buffer)
|
||||
{
|
||||
const u64 current_offset = m_block_count * m_block_size;
|
||||
const u64 i = current_offset / CLUSTER_SIZE;
|
||||
|
||||
size_t read_bytes = 0;
|
||||
if (m_is_scrubbing && m_free_table[i])
|
||||
if (CanBlockBeScrubbed(current_offset))
|
||||
{
|
||||
DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, current_offset);
|
||||
std::fill(buffer, buffer + m_block_size, 0x00);
|
||||
@@ -92,6 +84,11 @@ size_t DiscScrubber::GetNextBlock(File::IOFile& in, u8* buffer)
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
bool DiscScrubber::CanBlockBeScrubbed(u64 offset) const
|
||||
{
|
||||
return m_is_scrubbing && m_free_table[offset / CLUSTER_SIZE];
|
||||
}
|
||||
|
||||
void DiscScrubber::MarkAsUsed(u64 offset, u64 size)
|
||||
{
|
||||
u64 current_offset = offset;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Common/CommonTypes.h"
|
||||
@@ -35,8 +34,9 @@ public:
|
||||
DiscScrubber();
|
||||
~DiscScrubber();
|
||||
|
||||
bool SetupScrub(const std::string& filename, int block_size);
|
||||
bool SetupScrub(const Volume* disc, int block_size);
|
||||
size_t GetNextBlock(File::IOFile& in, u8* buffer);
|
||||
bool CanBlockBeScrubbed(u64 offset) const;
|
||||
|
||||
private:
|
||||
struct PartitionHeader final
|
||||
@@ -68,8 +68,7 @@ private:
|
||||
bool ParsePartitionData(const Partition& partition, PartitionHeader* header);
|
||||
void ParseFileSystemData(u64 partition_data_offset, const FileInfo& directory);
|
||||
|
||||
std::string m_filename;
|
||||
std::unique_ptr<Volume> m_disc;
|
||||
const Volume* m_disc;
|
||||
|
||||
std::vector<u8> m_free_table;
|
||||
u64 m_file_size = 0;
|
||||
|
||||
@@ -24,8 +24,9 @@ public:
|
||||
static std::unique_ptr<DriveReader> Create(const std::string& drive);
|
||||
~DriveReader();
|
||||
BlobType GetBlobType() const override { return BlobType::DRIVE; }
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
bool IsDataSizeAccurate() const override { return true; }
|
||||
|
||||
private:
|
||||
DriveReader(const std::string& drive);
|
||||
|
||||
@@ -145,7 +145,8 @@ Country TypicalCountryForRegion(Region region)
|
||||
}
|
||||
}
|
||||
|
||||
Region CountryCodeToRegion(u8 country_code, Platform platform, Region expected_region)
|
||||
Region CountryCodeToRegion(u8 country_code, Platform platform, Region expected_region,
|
||||
std::optional<u16> revision)
|
||||
{
|
||||
switch (country_code)
|
||||
{
|
||||
@@ -159,11 +160,24 @@ Region CountryCodeToRegion(u8 country_code, Platform platform, Region expected_r
|
||||
return Region::NTSC_J; // Korean GC games in English or Taiwanese Wii games
|
||||
|
||||
case 'E':
|
||||
if (expected_region == Region::NTSC_J)
|
||||
return Region::NTSC_J; // Korean GC games in English
|
||||
else
|
||||
if (platform != Platform::GameCubeDisc)
|
||||
return Region::NTSC_U; // The most common country code for NTSC-U
|
||||
|
||||
if (revision)
|
||||
{
|
||||
if (*revision >= 0x30)
|
||||
return Region::NTSC_J; // Korean GC games in English
|
||||
else
|
||||
return Region::NTSC_U; // The most common country code for NTSC-U
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expected_region == Region::NTSC_J)
|
||||
return Region::NTSC_J; // Korean GC games in English
|
||||
else
|
||||
return Region::NTSC_U; // The most common country code for NTSC-U
|
||||
}
|
||||
|
||||
case 'B':
|
||||
case 'N':
|
||||
return Region::NTSC_U;
|
||||
@@ -198,7 +212,8 @@ Region CountryCodeToRegion(u8 country_code, Platform platform, Region expected_r
|
||||
}
|
||||
}
|
||||
|
||||
Country CountryCodeToCountry(u8 country_code, Platform platform, Region region)
|
||||
Country CountryCodeToCountry(u8 country_code, Platform platform, Region region,
|
||||
std::optional<u16> revision)
|
||||
{
|
||||
switch (country_code)
|
||||
{
|
||||
@@ -214,10 +229,10 @@ Country CountryCodeToCountry(u8 country_code, Platform platform, Region region)
|
||||
return region == Region::NTSC_U ? Country::USA : Country::Europe;
|
||||
|
||||
case 'W':
|
||||
if (region == Region::PAL)
|
||||
return Country::Europe; // Only the Nordic version of Ratatouille (Wii)
|
||||
else if (platform == Platform::GameCubeDisc)
|
||||
if (platform == Platform::GameCubeDisc)
|
||||
return Country::Korea; // GC games in English released in Korea
|
||||
else if (region == Region::PAL)
|
||||
return Country::Europe; // Only the Nordic version of Ratatouille (Wii)
|
||||
else
|
||||
return Country::Taiwan; // Wii games in traditional Chinese released in Taiwan
|
||||
|
||||
@@ -251,11 +266,24 @@ Country CountryCodeToCountry(u8 country_code, Platform platform, Region region)
|
||||
|
||||
// NTSC
|
||||
case 'E':
|
||||
if (region == Region::NTSC_J)
|
||||
return Country::Korea; // GC games in English released in Korea
|
||||
else
|
||||
if (platform != Platform::GameCubeDisc)
|
||||
return Country::USA; // The most common country code for NTSC-U
|
||||
|
||||
if (revision)
|
||||
{
|
||||
if (*revision >= 0x30)
|
||||
return Country::Korea; // GC games in English released in Korea
|
||||
else
|
||||
return Country::USA; // The most common country code for NTSC-U
|
||||
}
|
||||
else
|
||||
{
|
||||
if (region == Region::NTSC_J)
|
||||
return Country::Korea; // GC games in English released in Korea
|
||||
else
|
||||
return Country::USA; // The most common country code for NTSC-U
|
||||
}
|
||||
|
||||
case 'B': // PAL games released on NTSC-U VC
|
||||
case 'N': // NTSC-J games released on NTSC-U VC
|
||||
return Country::USA;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
@@ -78,8 +79,10 @@ bool IsNTSC(Region region);
|
||||
Country TypicalCountryForRegion(Region region);
|
||||
// Avoid using this function if you can. Country codes aren't always reliable region indicators.
|
||||
Region CountryCodeToRegion(u8 country_code, Platform platform,
|
||||
Region expected_region = Region::Unknown);
|
||||
Country CountryCodeToCountry(u8 country_code, Platform platform, Region region = Region::Unknown);
|
||||
Region expected_region = Region::Unknown,
|
||||
std::optional<u16> revision = {});
|
||||
Country CountryCodeToCountry(u8 country_code, Platform platform, Region region = Region::Unknown,
|
||||
std::optional<u16> revision = {});
|
||||
|
||||
Region GetSysMenuRegion(u16 title_version);
|
||||
std::string GetSysMenuVersionString(u16 title_version);
|
||||
|
||||
@@ -20,8 +20,9 @@ public:
|
||||
static std::unique_ptr<PlainFileReader> Create(File::IOFile file);
|
||||
|
||||
BlobType GetBlobType() const override { return BlobType::PLAIN; }
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
bool IsDataSizeAccurate() const override { return true; }
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -43,8 +43,9 @@ public:
|
||||
static std::unique_ptr<TGCFileReader> Create(File::IOFile file);
|
||||
|
||||
BlobType GetBlobType() const override { return BlobType::TGC; }
|
||||
u64 GetDataSize() const override;
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
u64 GetDataSize() const override;
|
||||
bool IsDataSizeAccurate() const override { return true; }
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
|
||||
private:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user