Make the support for unencrypted Wii disc images less broken
These disc images are only used on dev units and not retail units. There are two important differences compared to normal Wii disc images: - The data starts 0x8000 bytes into each partition instead of 0x20000 - The data of a partition is stored unencrypted and contains no hashes Our old implementation was just guesswork and doesn't work at all. According to testing by GerbilSoft, this commit's implementation is able to read and extract files in the filesystem correctly, but the tested game still isn't able to boot. (It's thanks to their info about unencrypted disc images that I was able to make this commit.)
This commit is contained in:
parent
56e91bfdc1
commit
58743416bb
|
@ -1142,7 +1142,7 @@ void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u
|
||||||
// The variable dvd_offset tracks the actual offset on the DVD
|
// The variable dvd_offset tracks the actual offset on the DVD
|
||||||
// that the disc drive starts reading at, which differs in two ways:
|
// that the disc drive starts reading at, which differs in two ways:
|
||||||
// It's rounded to a whole ECC block and never uses Wii partition addressing.
|
// It's rounded to a whole ECC block and never uses Wii partition addressing.
|
||||||
u64 dvd_offset = DiscIO::VolumeWii::PartitionOffsetToRawOffset(offset, partition);
|
u64 dvd_offset = DVDThread::PartitionOffsetToRawOffset(offset, partition);
|
||||||
dvd_offset = Common::AlignDown(dvd_offset, DVD_ECC_BLOCK_SIZE);
|
dvd_offset = Common::AlignDown(dvd_offset, DVD_ECC_BLOCK_SIZE);
|
||||||
|
|
||||||
if (SConfig::GetInstance().bFastDiscSpeed)
|
if (SConfig::GetInstance().bFastDiscSpeed)
|
||||||
|
@ -1209,7 +1209,9 @@ void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u
|
||||||
u32 unbuffered_blocks = 0;
|
u32 unbuffered_blocks = 0;
|
||||||
|
|
||||||
const u32 bytes_per_chunk =
|
const u32 bytes_per_chunk =
|
||||||
partition == DiscIO::PARTITION_NONE ? DVD_ECC_BLOCK_SIZE : DiscIO::VolumeWii::BLOCK_DATA_SIZE;
|
partition != DiscIO::PARTITION_NONE && DVDThread::IsEncryptedAndHashed() ?
|
||||||
|
DiscIO::VolumeWii::BLOCK_DATA_SIZE :
|
||||||
|
DVD_ECC_BLOCK_SIZE;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,12 +186,24 @@ bool HasDisc()
|
||||||
return s_disc != nullptr;
|
return s_disc != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsEncryptedAndHashed()
|
||||||
|
{
|
||||||
|
// IsEncryptedAndHashed is thread-safe, so calling WaitUntilIdle isn't necessary.
|
||||||
|
return s_disc->IsEncryptedAndHashed();
|
||||||
|
}
|
||||||
|
|
||||||
DiscIO::Platform GetDiscType()
|
DiscIO::Platform GetDiscType()
|
||||||
{
|
{
|
||||||
// GetVolumeType is thread-safe, so calling WaitUntilIdle isn't necessary.
|
// GetVolumeType is thread-safe, so calling WaitUntilIdle isn't necessary.
|
||||||
return s_disc->GetVolumeType();
|
return s_disc->GetVolumeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition)
|
||||||
|
{
|
||||||
|
// PartitionOffsetToRawOffset is thread-safe, so calling WaitUntilIdle isn't necessary.
|
||||||
|
return s_disc->PartitionOffsetToRawOffset(offset, partition);
|
||||||
|
}
|
||||||
|
|
||||||
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition)
|
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition)
|
||||||
{
|
{
|
||||||
WaitUntilIdle();
|
WaitUntilIdle();
|
||||||
|
|
|
@ -42,7 +42,9 @@ void DoState(PointerWrap& p);
|
||||||
void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
|
void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
|
||||||
bool HasDisc();
|
bool HasDisc();
|
||||||
|
|
||||||
|
bool IsEncryptedAndHashed();
|
||||||
DiscIO::Platform GetDiscType();
|
DiscIO::Platform GetDiscType();
|
||||||
|
u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
|
||||||
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
|
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
|
||||||
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
|
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
|
||||||
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
|
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
|
||||||
|
|
|
@ -54,6 +54,8 @@ enum class PartitionType : u32
|
||||||
// 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J
|
// 0xFF is an arbitrarily picked value. Note that we can't use 0x00, because that means NTSC-J
|
||||||
constexpr u32 INVALID_REGION = 0xFF;
|
constexpr u32 INVALID_REGION = 0xFF;
|
||||||
|
|
||||||
|
constexpr u32 PARTITION_DATA_OFFSET = 0x20000;
|
||||||
|
|
||||||
constexpr u8 ENTRY_SIZE = 0x0c;
|
constexpr u8 ENTRY_SIZE = 0x0c;
|
||||||
constexpr u8 FILE_ENTRY = 0;
|
constexpr u8 FILE_ENTRY = 0;
|
||||||
constexpr u8 DIRECTORY_ENTRY = 1;
|
constexpr u8 DIRECTORY_ENTRY = 1;
|
||||||
|
@ -508,8 +510,8 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti
|
||||||
|
|
||||||
const u64 partition_data_size = partitions[i].partition.GetDataSize();
|
const u64 partition_data_size = partitions[i].partition.GetDataSize();
|
||||||
m_partitions.emplace(partition_address, std::move(partitions[i].partition));
|
m_partitions.emplace(partition_address, std::move(partitions[i].partition));
|
||||||
const u64 unaligned_next_partition_address =
|
const u64 unaligned_next_partition_address = VolumeWii::EncryptedPartitionOffsetToRawOffset(
|
||||||
VolumeWii::PartitionOffsetToRawOffset(partition_data_size, Partition(partition_address));
|
partition_data_size, Partition(partition_address), PARTITION_DATA_OFFSET);
|
||||||
partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull);
|
partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull);
|
||||||
}
|
}
|
||||||
m_data_size = partition_address;
|
m_data_size = partition_address;
|
||||||
|
@ -546,7 +548,6 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti
|
||||||
partition_root + "h3.bin");
|
partition_root + "h3.bin");
|
||||||
|
|
||||||
constexpr u32 PARTITION_HEADER_SIZE = 0x1c;
|
constexpr u32 PARTITION_HEADER_SIZE = 0x1c;
|
||||||
constexpr u32 DATA_OFFSET = 0x20000;
|
|
||||||
const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000;
|
const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000;
|
||||||
m_partition_headers.emplace_back(PARTITION_HEADER_SIZE);
|
m_partition_headers.emplace_back(PARTITION_HEADER_SIZE);
|
||||||
std::vector<u8>& partition_header = m_partition_headers.back();
|
std::vector<u8>& partition_header = m_partition_headers.back();
|
||||||
|
@ -555,7 +556,7 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti
|
||||||
Write32(static_cast<u32>(cert_size), 0x8, &partition_header);
|
Write32(static_cast<u32>(cert_size), 0x8, &partition_header);
|
||||||
Write32(static_cast<u32>(cert_offset >> 2), 0x0C, &partition_header);
|
Write32(static_cast<u32>(cert_offset >> 2), 0x0C, &partition_header);
|
||||||
Write32(H3_OFFSET >> 2, 0x10, &partition_header);
|
Write32(H3_OFFSET >> 2, 0x10, &partition_header);
|
||||||
Write32(DATA_OFFSET >> 2, 0x14, &partition_header);
|
Write32(PARTITION_DATA_OFFSET >> 2, 0x14, &partition_header);
|
||||||
Write32(static_cast<u32>(data_size >> 2), 0x18, &partition_header);
|
Write32(static_cast<u32>(data_size >> 2), 0x18, &partition_header);
|
||||||
|
|
||||||
m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header);
|
m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header);
|
||||||
|
|
|
@ -361,7 +361,8 @@ bool ExportSystemData(const Volume& volume, const Partition& partition,
|
||||||
success &= ExportTicket(volume, partition, export_folder + "/ticket.bin");
|
success &= ExportTicket(volume, partition, export_folder + "/ticket.bin");
|
||||||
success &= ExportTMD(volume, partition, export_folder + "/tmd.bin");
|
success &= ExportTMD(volume, partition, export_folder + "/tmd.bin");
|
||||||
success &= ExportCertificateChain(volume, partition, export_folder + "/cert.bin");
|
success &= ExportCertificateChain(volume, partition, export_folder + "/cert.bin");
|
||||||
success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin");
|
if (volume.IsEncryptedAndHashed())
|
||||||
|
success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
return temp ? static_cast<u64>(*temp) << GetOffsetShift() : std::optional<u64>();
|
return temp ? static_cast<u64>(*temp) << GetOffsetShift() : std::optional<u64>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool IsEncryptedAndHashed() const { return false; }
|
||||||
virtual std::vector<Partition> GetPartitions() const { return {}; }
|
virtual std::vector<Partition> GetPartitions() const { return {}; }
|
||||||
virtual Partition GetGamePartition() const { return PARTITION_NONE; }
|
virtual Partition GetGamePartition() const { return PARTITION_NONE; }
|
||||||
virtual std::optional<u32> GetPartitionType(const Partition& partition) const { return {}; }
|
virtual std::optional<u32> GetPartitionType(const Partition& partition) const { return {}; }
|
||||||
|
@ -70,6 +71,10 @@ public:
|
||||||
virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; }
|
virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; }
|
||||||
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
|
// 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 const FileSystem* GetFileSystem(const Partition& partition) const = 0;
|
||||||
|
virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
std::string GetGameID() const { return GetGameID(GetGamePartition()); }
|
std::string GetGameID() const { return GetGameID(GetGamePartition()); }
|
||||||
virtual std::string GetGameID(const Partition& partition) const = 0;
|
virtual std::string GetGameID(const Partition& partition) const = 0;
|
||||||
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }
|
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }
|
||||||
|
|
|
@ -33,19 +33,13 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
constexpr u64 PARTITION_DATA_OFFSET = 0x20000;
|
|
||||||
|
|
||||||
VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
|
VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
|
||||||
: m_pReader(std::move(reader)), m_game_partition(PARTITION_NONE),
|
: m_pReader(std::move(reader)), m_game_partition(PARTITION_NONE),
|
||||||
m_last_decrypted_block(UINT64_MAX)
|
m_last_decrypted_block(UINT64_MAX)
|
||||||
{
|
{
|
||||||
ASSERT(m_pReader);
|
ASSERT(m_pReader);
|
||||||
|
|
||||||
if (m_pReader->ReadSwapped<u32>(0x60) != u32(0))
|
m_encrypted = m_pReader->ReadSwapped<u32>(0x60) == u32(0);
|
||||||
{
|
|
||||||
// No partitions - just read unencrypted data like with a GC disc
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 partition_group = 0; partition_group < 4; ++partition_group)
|
for (u32 partition_group = 0; partition_group < 4; ++partition_group)
|
||||||
{
|
{
|
||||||
|
@ -118,12 +112,16 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
|
||||||
return file_system->IsValid() ? std::move(file_system) : nullptr;
|
return file_system->IsValid() ? std::move(file_system) : nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto get_data_offset = [this, partition]() -> u64 {
|
||||||
|
return ReadSwappedAndShifted(partition.offset + 0x2b8, PARTITION_NONE).value_or(0);
|
||||||
|
};
|
||||||
|
|
||||||
m_partitions.emplace(
|
m_partitions.emplace(
|
||||||
partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key),
|
partition, PartitionDetails{Common::Lazy<std::unique_ptr<mbedtls_aes_context>>(get_key),
|
||||||
Common::Lazy<IOS::ES::TicketReader>(get_ticket),
|
Common::Lazy<IOS::ES::TicketReader>(get_ticket),
|
||||||
Common::Lazy<IOS::ES::TMDReader>(get_tmd),
|
Common::Lazy<IOS::ES::TMDReader>(get_tmd),
|
||||||
Common::Lazy<std::unique_ptr<FileSystem>>(get_file_system),
|
Common::Lazy<std::unique_ptr<FileSystem>>(get_file_system),
|
||||||
*partition_type});
|
Common::Lazy<u64>(get_data_offset), *partition_type});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,14 +135,21 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
|
||||||
if (partition == PARTITION_NONE)
|
if (partition == PARTITION_NONE)
|
||||||
return m_pReader->Read(_ReadOffset, _Length, _pBuffer);
|
return m_pReader->Read(_ReadOffset, _Length, _pBuffer);
|
||||||
|
|
||||||
if (m_pReader->SupportsReadWiiDecrypted())
|
|
||||||
return m_pReader->ReadWiiDecrypted(_ReadOffset, _Length, _pBuffer, partition.offset);
|
|
||||||
|
|
||||||
// Get the decryption key for the partition
|
|
||||||
auto it = m_partitions.find(partition);
|
auto it = m_partitions.find(partition);
|
||||||
if (it == m_partitions.end())
|
if (it == m_partitions.end())
|
||||||
return false;
|
return false;
|
||||||
mbedtls_aes_context* aes_context = it->second.key->get();
|
const PartitionDetails& partition_details = it->second;
|
||||||
|
|
||||||
|
if (!m_encrypted)
|
||||||
|
{
|
||||||
|
return m_pReader->Read(partition.offset + *partition_details.data_offset + _ReadOffset, _Length,
|
||||||
|
_pBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pReader->SupportsReadWiiDecrypted())
|
||||||
|
return m_pReader->ReadWiiDecrypted(_ReadOffset, _Length, _pBuffer, partition.offset);
|
||||||
|
|
||||||
|
mbedtls_aes_context* aes_context = partition_details.key->get();
|
||||||
if (!aes_context)
|
if (!aes_context)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -152,8 +157,8 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
|
||||||
while (_Length > 0)
|
while (_Length > 0)
|
||||||
{
|
{
|
||||||
// Calculate offsets
|
// Calculate offsets
|
||||||
u64 block_offset_on_disc =
|
u64 block_offset_on_disc = partition.offset + *partition_details.data_offset +
|
||||||
partition.offset + PARTITION_DATA_OFFSET + _ReadOffset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE;
|
_ReadOffset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE;
|
||||||
u64 data_offset_in_block = _ReadOffset % BLOCK_DATA_SIZE;
|
u64 data_offset_in_block = _ReadOffset % BLOCK_DATA_SIZE;
|
||||||
|
|
||||||
if (m_last_decrypted_block != block_offset_on_disc)
|
if (m_last_decrypted_block != block_offset_on_disc)
|
||||||
|
@ -190,6 +195,11 @@ bool VolumeWii::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, const Partition
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VolumeWii::IsEncryptedAndHashed() const
|
||||||
|
{
|
||||||
|
return m_encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Partition> VolumeWii::GetPartitions() const
|
std::vector<Partition> VolumeWii::GetPartitions() const
|
||||||
{
|
{
|
||||||
std::vector<Partition> partitions;
|
std::vector<Partition> partitions;
|
||||||
|
@ -235,15 +245,29 @@ const FileSystem* VolumeWii::GetFileSystem(const Partition& partition) const
|
||||||
return it != m_partitions.end() ? it->second.file_system->get() : nullptr;
|
return it != m_partitions.end() ? it->second.file_system->get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition)
|
u64 VolumeWii::EncryptedPartitionOffsetToRawOffset(u64 offset, const Partition& partition,
|
||||||
|
u64 partition_data_offset)
|
||||||
{
|
{
|
||||||
if (partition == PARTITION_NONE)
|
if (partition == PARTITION_NONE)
|
||||||
return offset;
|
return offset;
|
||||||
|
|
||||||
return partition.offset + PARTITION_DATA_OFFSET + (offset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE) +
|
return partition.offset + partition_data_offset + (offset / BLOCK_DATA_SIZE * BLOCK_TOTAL_SIZE) +
|
||||||
(offset % BLOCK_DATA_SIZE);
|
(offset % BLOCK_DATA_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 VolumeWii::PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
|
||||||
|
{
|
||||||
|
auto it = m_partitions.find(partition);
|
||||||
|
if (it == m_partitions.end())
|
||||||
|
return offset;
|
||||||
|
const u64 data_offset = *it->second.data_offset;
|
||||||
|
|
||||||
|
if (!m_encrypted)
|
||||||
|
return partition.offset + data_offset + offset;
|
||||||
|
|
||||||
|
return EncryptedPartitionOffsetToRawOffset(offset, partition, data_offset);
|
||||||
|
}
|
||||||
|
|
||||||
std::string VolumeWii::GetGameID(const Partition& partition) const
|
std::string VolumeWii::GetGameID(const Partition& partition) const
|
||||||
{
|
{
|
||||||
char ID[6];
|
char ID[6];
|
||||||
|
@ -357,11 +381,15 @@ u64 VolumeWii::GetRawSize() const
|
||||||
|
|
||||||
bool VolumeWii::CheckIntegrity(const Partition& partition) const
|
bool VolumeWii::CheckIntegrity(const Partition& partition) const
|
||||||
{
|
{
|
||||||
|
if (!m_encrypted)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Get the decryption key for the partition
|
// Get the decryption key for the partition
|
||||||
auto it = m_partitions.find(partition);
|
auto it = m_partitions.find(partition);
|
||||||
if (it == m_partitions.end())
|
if (it == m_partitions.end())
|
||||||
return false;
|
return false;
|
||||||
mbedtls_aes_context* aes_context = it->second.key->get();
|
const PartitionDetails& partition_details = it->second;
|
||||||
|
mbedtls_aes_context* aes_context = partition_details.key->get();
|
||||||
if (!aes_context)
|
if (!aes_context)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -373,7 +401,7 @@ bool VolumeWii::CheckIntegrity(const Partition& partition) const
|
||||||
u32 nClusters = (u32)(partDataSize / 0x8000);
|
u32 nClusters = (u32)(partDataSize / 0x8000);
|
||||||
for (u32 clusterID = 0; clusterID < nClusters; ++clusterID)
|
for (u32 clusterID = 0; clusterID < nClusters; ++clusterID)
|
||||||
{
|
{
|
||||||
u64 clusterOff = partition.offset + PARTITION_DATA_OFFSET + (u64)clusterID * 0x8000;
|
u64 clusterOff = partition.offset + *partition_details.data_offset + (u64)clusterID * 0x8000;
|
||||||
|
|
||||||
// Read and decrypt the cluster metadata
|
// Read and decrypt the cluster metadata
|
||||||
u8 clusterMDCrypted[0x400];
|
u8 clusterMDCrypted[0x400];
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
VolumeWii(std::unique_ptr<BlobReader> reader);
|
VolumeWii(std::unique_ptr<BlobReader> reader);
|
||||||
~VolumeWii();
|
~VolumeWii();
|
||||||
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& partition) const override;
|
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& partition) const override;
|
||||||
|
bool IsEncryptedAndHashed() const override;
|
||||||
std::vector<Partition> GetPartitions() const override;
|
std::vector<Partition> GetPartitions() const override;
|
||||||
Partition GetGamePartition() const override;
|
Partition GetGamePartition() const override;
|
||||||
std::optional<u32> GetPartitionType(const Partition& partition) const override;
|
std::optional<u32> GetPartitionType(const Partition& partition) const override;
|
||||||
|
@ -40,6 +41,9 @@ public:
|
||||||
const IOS::ES::TicketReader& GetTicket(const Partition& partition) const override;
|
const IOS::ES::TicketReader& GetTicket(const Partition& partition) const override;
|
||||||
const IOS::ES::TMDReader& GetTMD(const Partition& partition) const override;
|
const IOS::ES::TMDReader& GetTMD(const Partition& partition) const override;
|
||||||
const FileSystem* GetFileSystem(const Partition& partition) const override;
|
const FileSystem* GetFileSystem(const Partition& partition) const override;
|
||||||
|
static u64 EncryptedPartitionOffsetToRawOffset(u64 offset, const Partition& partition,
|
||||||
|
u64 partition_data_offset);
|
||||||
|
u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const override;
|
||||||
std::string GetGameID(const Partition& partition) const override;
|
std::string GetGameID(const Partition& partition) const override;
|
||||||
std::string GetMakerID(const Partition& partition) const override;
|
std::string GetMakerID(const Partition& partition) const override;
|
||||||
std::optional<u16> GetRevision(const Partition& partition) const override;
|
std::optional<u16> GetRevision(const Partition& partition) const override;
|
||||||
|
@ -59,8 +63,6 @@ public:
|
||||||
u64 GetSize() const override;
|
u64 GetSize() const override;
|
||||||
u64 GetRawSize() const override;
|
u64 GetRawSize() const override;
|
||||||
|
|
||||||
static u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition);
|
|
||||||
|
|
||||||
static constexpr unsigned int BLOCK_HEADER_SIZE = 0x0400;
|
static constexpr unsigned int BLOCK_HEADER_SIZE = 0x0400;
|
||||||
static constexpr unsigned int BLOCK_DATA_SIZE = 0x7C00;
|
static constexpr unsigned int BLOCK_DATA_SIZE = 0x7C00;
|
||||||
static constexpr unsigned int BLOCK_TOTAL_SIZE = BLOCK_HEADER_SIZE + BLOCK_DATA_SIZE;
|
static constexpr unsigned int BLOCK_TOTAL_SIZE = BLOCK_HEADER_SIZE + BLOCK_DATA_SIZE;
|
||||||
|
@ -75,12 +77,14 @@ private:
|
||||||
Common::Lazy<IOS::ES::TicketReader> ticket;
|
Common::Lazy<IOS::ES::TicketReader> ticket;
|
||||||
Common::Lazy<IOS::ES::TMDReader> tmd;
|
Common::Lazy<IOS::ES::TMDReader> tmd;
|
||||||
Common::Lazy<std::unique_ptr<FileSystem>> file_system;
|
Common::Lazy<std::unique_ptr<FileSystem>> file_system;
|
||||||
|
Common::Lazy<u64> data_offset;
|
||||||
u32 type;
|
u32 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<BlobReader> m_pReader;
|
std::unique_ptr<BlobReader> m_pReader;
|
||||||
std::map<Partition, PartitionDetails> m_partitions;
|
std::map<Partition, PartitionDetails> m_partitions;
|
||||||
Partition m_game_partition;
|
Partition m_game_partition;
|
||||||
|
bool m_encrypted;
|
||||||
|
|
||||||
mutable u64 m_last_decrypted_block;
|
mutable u64 m_last_decrypted_block;
|
||||||
mutable u8 m_last_decrypted_block_data[BLOCK_DATA_SIZE];
|
mutable u8 m_last_decrypted_block_data[BLOCK_DATA_SIZE];
|
||||||
|
|
|
@ -219,9 +219,12 @@ void FilesystemWidget::ShowContextMenu(const QPoint&)
|
||||||
if (!folder.isEmpty())
|
if (!folder.isEmpty())
|
||||||
ExtractPartition(partition, folder);
|
ExtractPartition(partition, folder);
|
||||||
});
|
});
|
||||||
menu->addSeparator();
|
if (m_volume->IsEncryptedAndHashed())
|
||||||
AddAction(menu, tr("Check Partition Integrity"), this,
|
{
|
||||||
[this, partition] { CheckIntegrity(partition); });
|
menu->addSeparator();
|
||||||
|
AddAction(menu, tr("Check Partition Integrity"), this,
|
||||||
|
[this, partition] { CheckIntegrity(partition); });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EntryType::File:
|
case EntryType::File:
|
||||||
AddAction(menu, tr("Extract File..."), this, [this, partition, path] {
|
AddAction(menu, tr("Extract File..."), this, [this, partition, path] {
|
||||||
|
|
|
@ -204,7 +204,7 @@ void FilesystemPanel::OnRightClickTree(wxTreeEvent& event)
|
||||||
else
|
else
|
||||||
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Partition..."));
|
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Partition..."));
|
||||||
|
|
||||||
if (first_visible_item != selection)
|
if (first_visible_item != selection && m_opened_iso->IsEncryptedAndHashed())
|
||||||
{
|
{
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
|
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
|
||||||
|
|
Loading…
Reference in New Issue