mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-30 04:21:16 +00:00
RVZ: Support chunk sizes between 32 KiB and 2 MiB
WIA doesn't support smaller than 2 MiB.
This commit is contained in:
parent
0d433baeb5
commit
b06c50ed2e
@ -27,6 +27,7 @@
|
|||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
|
|
||||||
@ -124,8 +125,12 @@ bool WIAFileReader::Initialize(const std::string& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u32 chunk_size = Common::swap32(m_header_2.chunk_size);
|
const u32 chunk_size = Common::swap32(m_header_2.chunk_size);
|
||||||
if (chunk_size % VolumeWii::GROUP_TOTAL_SIZE != 0)
|
const auto is_power_of_two = [](u32 x) { return (x & (x - 1)) == 0; };
|
||||||
|
if ((!m_rvz || chunk_size < VolumeWii::BLOCK_TOTAL_SIZE || !is_power_of_two(chunk_size)) &&
|
||||||
|
chunk_size % VolumeWii::GROUP_TOTAL_SIZE != 0)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const u32 compression_type = Common::swap32(m_header_2.compression_type);
|
const u32 compression_type = Common::swap32(m_header_2.compression_type);
|
||||||
m_compression_type = static_cast<WIACompressionType>(compression_type);
|
m_compression_type = static_cast<WIACompressionType>(compression_type);
|
||||||
@ -319,19 +324,20 @@ bool WIAFileReader::Read(u64 offset, u64 size, u8* out_ptr)
|
|||||||
|
|
||||||
const u64 bytes_to_read = std::min(data_size - (offset - data_offset), size);
|
const u64 bytes_to_read = std::min(data_size - (offset - data_offset), size);
|
||||||
|
|
||||||
|
m_exception_list.clear();
|
||||||
|
m_write_to_exception_list = true;
|
||||||
|
m_exception_list_last_group_index = std::numeric_limits<u64>::max();
|
||||||
|
Common::ScopeGuard guard([this] { m_write_to_exception_list = false; });
|
||||||
|
|
||||||
bool hash_exception_error = false;
|
bool hash_exception_error = false;
|
||||||
if (!m_encryption_cache.EncryptGroups(
|
if (!m_encryption_cache.EncryptGroups(
|
||||||
offset - partition_data_offset, bytes_to_read, out_ptr, partition_data_offset,
|
offset - partition_data_offset, bytes_to_read, out_ptr, partition_data_offset,
|
||||||
partition_total_sectors * VolumeWii::BLOCK_DATA_SIZE, partition.partition_key,
|
partition_total_sectors * VolumeWii::BLOCK_DATA_SIZE, partition.partition_key,
|
||||||
[this, chunk_size, first_sector, partition_first_sector, &hash_exception_error](
|
[this, &hash_exception_error](
|
||||||
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP], u64 offset) {
|
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP], u64 offset) {
|
||||||
const u64 partition_part_offset =
|
// EncryptGroups calls ReadWiiDecrypted, which calls ReadFromGroups,
|
||||||
(first_sector - partition_first_sector) * VolumeWii::BLOCK_TOTAL_SIZE;
|
// which populates m_exception_list when m_write_to_exception_list == true
|
||||||
const u64 index =
|
if (!ApplyHashExceptions(m_exception_list, hash_blocks))
|
||||||
(offset - partition_part_offset) % chunk_size / VolumeWii::GROUP_TOTAL_SIZE;
|
|
||||||
|
|
||||||
// EncryptGroups calls ReadWiiDecrypted, which populates m_cached_chunk
|
|
||||||
if (!m_cached_chunk.ApplyHashExceptions(hash_blocks, index))
|
|
||||||
hash_exception_error = true;
|
hash_exception_error = true;
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
@ -392,7 +398,7 @@ bool WIAFileReader::ReadWiiDecrypted(u64 offset, u64 size, u8* out_ptr, u64 part
|
|||||||
if (!ReadFromGroups(&offset, &size, &out_ptr, chunk_size, VolumeWii::BLOCK_DATA_SIZE,
|
if (!ReadFromGroups(&offset, &size, &out_ptr, chunk_size, VolumeWii::BLOCK_DATA_SIZE,
|
||||||
data_offset, data_size, Common::swap32(data.group_index),
|
data_offset, data_size, Common::swap32(data.group_index),
|
||||||
Common::swap32(data.number_of_groups),
|
Common::swap32(data.number_of_groups),
|
||||||
chunk_size / VolumeWii::GROUP_DATA_SIZE))
|
std::max<u64>(1, chunk_size / VolumeWii::GROUP_DATA_SIZE)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -423,10 +429,10 @@ bool WIAFileReader::ReadFromGroups(u64* offset, u64* size, u8** out_ptr, u64 chu
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const GroupEntry group = m_group_entries[total_group_index];
|
const GroupEntry group = m_group_entries[total_group_index];
|
||||||
const u64 group_offset = data_offset + i * chunk_size;
|
const u64 group_offset_in_data = i * chunk_size;
|
||||||
const u64 offset_in_group = *offset - group_offset;
|
const u64 offset_in_group = *offset - group_offset_in_data - data_offset;
|
||||||
|
|
||||||
chunk_size = std::min(chunk_size, data_offset + data_size - group_offset);
|
chunk_size = std::min(chunk_size, data_size - group_offset_in_data);
|
||||||
|
|
||||||
const u64 bytes_to_read = std::min(chunk_size - offset_in_group, *size);
|
const u64 bytes_to_read = std::min(chunk_size - offset_in_group, *size);
|
||||||
const u32 group_data_size = Common::swap32(group.data_size);
|
const u32 group_data_size = Common::swap32(group.data_size);
|
||||||
@ -444,6 +450,17 @@ bool WIAFileReader::ReadFromGroups(u64* offset, u64* size, u8** out_ptr, u64 chu
|
|||||||
m_cached_chunk_offset = std::numeric_limits<u64>::max(); // Invalidate the cache
|
m_cached_chunk_offset = std::numeric_limits<u64>::max(); // Invalidate the cache
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_write_to_exception_list && m_exception_list_last_group_index != total_group_index)
|
||||||
|
{
|
||||||
|
const u64 exception_list_index = offset_in_group / VolumeWii::GROUP_DATA_SIZE;
|
||||||
|
const u16 additional_offset =
|
||||||
|
static_cast<u16>(group_offset_in_data % VolumeWii::GROUP_DATA_SIZE /
|
||||||
|
VolumeWii::BLOCK_DATA_SIZE * VolumeWii::BLOCK_HEADER_SIZE);
|
||||||
|
|
||||||
|
chunk.GetHashExceptions(&m_exception_list, exception_list_index, additional_offset);
|
||||||
|
m_exception_list_last_group_index = total_group_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*offset += bytes_to_read;
|
*offset += bytes_to_read;
|
||||||
@ -1306,13 +1323,13 @@ bool WIAFileReader::Chunk::HandleExceptions(const u8* data, size_t bytes_allocat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WIAFileReader::Chunk::ApplyHashExceptions(
|
void WIAFileReader::Chunk::GetHashExceptions(std::vector<HashExceptionEntry>* exception_list,
|
||||||
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP], u64 exception_list_index) const
|
u64 exception_list_index, u16 additional_offset) const
|
||||||
{
|
{
|
||||||
if (m_exception_lists > 0)
|
ASSERT(m_exception_lists == 0);
|
||||||
return false; // We still have exception lists left to read
|
|
||||||
|
|
||||||
const u8* data = m_compressed_exception_lists ? m_out.data.data() : m_in.data.data();
|
const u8* data_start = m_compressed_exception_lists ? m_out.data.data() : m_in.data.data();
|
||||||
|
const u8* data = data_start;
|
||||||
|
|
||||||
for (u64 i = exception_list_index; i > 0; --i)
|
for (u64 i = exception_list_index; i > 0; --i)
|
||||||
data += Common::swap16(data) * sizeof(HashExceptionEntry) + sizeof(u16);
|
data += Common::swap16(data) * sizeof(HashExceptionEntry) + sizeof(u16);
|
||||||
@ -1322,10 +1339,23 @@ bool WIAFileReader::Chunk::ApplyHashExceptions(
|
|||||||
|
|
||||||
for (size_t i = 0; i < exceptions; ++i)
|
for (size_t i = 0; i < exceptions; ++i)
|
||||||
{
|
{
|
||||||
HashExceptionEntry exception;
|
std::memcpy(&exception_list->emplace_back(), data, sizeof(HashExceptionEntry));
|
||||||
std::memcpy(&exception, data, sizeof(HashExceptionEntry));
|
|
||||||
data += sizeof(HashExceptionEntry);
|
data += sizeof(HashExceptionEntry);
|
||||||
|
|
||||||
|
u16& offset = exception_list->back().offset;
|
||||||
|
offset = Common::swap16(Common::swap16(offset) + additional_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(data <= data_start + (m_compressed_exception_lists ? m_out_bytes_used_for_exceptions :
|
||||||
|
m_in_bytes_used_for_exceptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WIAFileReader::ApplyHashExceptions(
|
||||||
|
const std::vector<HashExceptionEntry>& exception_list,
|
||||||
|
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP])
|
||||||
|
{
|
||||||
|
for (const HashExceptionEntry& exception : exception_list)
|
||||||
|
{
|
||||||
const u16 offset = Common::swap16(exception.offset);
|
const u16 offset = Common::swap16(exception.offset);
|
||||||
|
|
||||||
const size_t block_index = offset / VolumeWii::BLOCK_HEADER_SIZE;
|
const size_t block_index = offset / VolumeWii::BLOCK_HEADER_SIZE;
|
||||||
@ -1874,7 +1904,7 @@ WIAFileReader::ConvertToWIA(BlobReader* infile, const VolumeDisc* infile_volume,
|
|||||||
ASSERT(chunk_size > 0);
|
ASSERT(chunk_size > 0);
|
||||||
|
|
||||||
const u64 iso_size = infile->GetDataSize();
|
const u64 iso_size = infile->GetDataSize();
|
||||||
const u64 exception_lists_per_chunk = chunk_size / VolumeWii::GROUP_TOTAL_SIZE;
|
const u64 exception_lists_per_chunk = std::max<u64>(1, chunk_size / VolumeWii::GROUP_TOTAL_SIZE);
|
||||||
const bool compressed_exception_lists = compression_type > WIACompressionType::Purge;
|
const bool compressed_exception_lists = compression_type > WIACompressionType::Purge;
|
||||||
|
|
||||||
u64 bytes_read = 0;
|
u64 bytes_read = 0;
|
||||||
|
@ -381,8 +381,8 @@ private:
|
|||||||
bool Read(u64 offset, u64 size, u8* out_ptr);
|
bool Read(u64 offset, u64 size, u8* out_ptr);
|
||||||
|
|
||||||
// This can only be called once at least one byte of data has been read
|
// This can only be called once at least one byte of data has been read
|
||||||
bool ApplyHashExceptions(VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP],
|
void GetHashExceptions(std::vector<HashExceptionEntry>* exception_list,
|
||||||
u64 exception_list_index) const;
|
u64 exception_list_index, u16 additional_offset) const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool ReadAll(std::vector<T>* vector)
|
bool ReadAll(std::vector<T>* vector)
|
||||||
@ -419,6 +419,9 @@ private:
|
|||||||
Chunk& ReadCompressedData(u64 offset_in_file, u64 compressed_size, u64 decompressed_size,
|
Chunk& ReadCompressedData(u64 offset_in_file, u64 compressed_size, u64 decompressed_size,
|
||||||
u32 exception_lists);
|
u32 exception_lists);
|
||||||
|
|
||||||
|
static bool ApplyHashExceptions(const std::vector<HashExceptionEntry>& exception_list,
|
||||||
|
VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP]);
|
||||||
|
|
||||||
static std::string VersionToString(u32 version);
|
static std::string VersionToString(u32 version);
|
||||||
|
|
||||||
static u32 LZMA2DictionarySize(u8 p);
|
static u32 LZMA2DictionarySize(u8 p);
|
||||||
@ -536,6 +539,10 @@ private:
|
|||||||
u64 m_cached_chunk_offset = std::numeric_limits<u64>::max();
|
u64 m_cached_chunk_offset = std::numeric_limits<u64>::max();
|
||||||
WiiEncryptionCache m_encryption_cache;
|
WiiEncryptionCache m_encryption_cache;
|
||||||
|
|
||||||
|
std::vector<HashExceptionEntry> m_exception_list;
|
||||||
|
bool m_write_to_exception_list = false;
|
||||||
|
u64 m_exception_list_last_group_index;
|
||||||
|
|
||||||
WIAHeader1 m_header_1;
|
WIAHeader1 m_header_1;
|
||||||
WIAHeader2 m_header_2;
|
WIAHeader2 m_header_2;
|
||||||
std::vector<PartitionEntry> m_partition_entries;
|
std::vector<PartitionEntry> m_partition_entries;
|
||||||
|
@ -199,12 +199,18 @@ void ConvertDialog::OnFormatChanged()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DiscIO::BlobType::WIA:
|
case DiscIO::BlobType::WIA:
|
||||||
case DiscIO::BlobType::RVZ:
|
|
||||||
m_block_size->setEnabled(true);
|
m_block_size->setEnabled(true);
|
||||||
|
|
||||||
// This is the smallest block size supported by WIA. For performance, larger sizes are avoided.
|
// This is the smallest block size supported by WIA. For performance, larger sizes are avoided.
|
||||||
AddToBlockSizeComboBox(0x200000);
|
AddToBlockSizeComboBox(0x200000);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DiscIO::BlobType::RVZ:
|
||||||
|
m_block_size->setEnabled(true);
|
||||||
|
|
||||||
|
for (int block_size = MIN_BLOCK_SIZE; block_size <= MAX_BLOCK_SIZE; block_size *= 2)
|
||||||
|
AddToBlockSizeComboBox(block_size);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user