WIA: Add reading raw data
This commit is contained in:
parent
8da5d0c4fe
commit
2a5fcc9c25
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "DiscIO/WIABlob.h"
|
#include "DiscIO/WIABlob.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -46,16 +48,92 @@ bool WIAFileReader::Initialize(const std::string& path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Common::swap32(m_header_1.header_2_size) < sizeof(WIAHeader2))
|
const u32 header_2_size = Common::swap32(m_header_1.header_2_size);
|
||||||
|
const u32 header_2_min_size = sizeof(WIAHeader2) - sizeof(WIAHeader2::compressor_data);
|
||||||
|
if (header_2_size < header_2_min_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_file.ReadArray(&m_header_2, 1))
|
std::vector<u8> header_2(header_2_size);
|
||||||
|
if (!m_file.ReadBytes(header_2.data(), header_2.size()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
std::memcpy(&m_header_2, header_2.data(), std::min(header_2.size(), sizeof(WIAHeader2)));
|
||||||
|
|
||||||
|
if (m_header_2.compressor_data_size > sizeof(WIAHeader2::compressor_data) ||
|
||||||
|
header_2_size < header_2_min_size + m_header_2.compressor_data_size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
if (chunk_size % VolumeWii::GROUP_TOTAL_SIZE != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const u32 compression_type = Common::swap32(m_header_2.compression_type);
|
||||||
|
if (compression_type != 0)
|
||||||
|
{
|
||||||
|
ERROR_LOG(DISCIO, "Unsupported WIA compression type %u in %s", compression_type, path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t number_of_partition_entries = Common::swap32(m_header_2.number_of_partition_entries);
|
||||||
|
const size_t partition_entry_size = Common::swap32(m_header_2.partition_entry_size);
|
||||||
|
std::vector<u8> partition_entries(partition_entry_size * number_of_partition_entries);
|
||||||
|
if (!m_file.Seek(Common::swap64(m_header_2.partition_entries_offset), SEEK_SET))
|
||||||
|
return false;
|
||||||
|
if (!m_file.ReadBytes(partition_entries.data(), partition_entries.size()))
|
||||||
|
return false;
|
||||||
|
// TODO: Check hash
|
||||||
|
|
||||||
|
const size_t copy_length = std::min(partition_entry_size, sizeof(PartitionEntry));
|
||||||
|
const size_t memset_length = sizeof(PartitionEntry) - copy_length;
|
||||||
|
u8* ptr = partition_entries.data();
|
||||||
|
m_partition_entries.resize(number_of_partition_entries);
|
||||||
|
for (size_t i = 0; i < number_of_partition_entries; ++i, ptr += partition_entry_size)
|
||||||
|
{
|
||||||
|
std::memcpy(&m_partition_entries[i], ptr, copy_length);
|
||||||
|
std::memset(reinterpret_cast<u8*>(&m_partition_entries[i]) + copy_length, 0, memset_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const PartitionEntry& partition : m_partition_entries)
|
||||||
|
{
|
||||||
|
if (Common::swap32(partition.data_entries[1].number_of_sectors) != 0)
|
||||||
|
{
|
||||||
|
const u32 first_end = Common::swap32(partition.data_entries[0].first_sector) +
|
||||||
|
Common::swap32(partition.data_entries[0].number_of_sectors);
|
||||||
|
const u32 second_start = Common::swap32(partition.data_entries[1].first_sector);
|
||||||
|
if (first_end > second_start)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(m_partition_entries.begin(), m_partition_entries.end(),
|
||||||
|
[](const PartitionEntry& a, const PartitionEntry& b) {
|
||||||
|
return Common::swap32(a.data_entries[0].first_sector) <
|
||||||
|
Common::swap32(b.data_entries[0].first_sector);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Compression
|
||||||
|
const u32 number_of_raw_data_entries = Common::swap32(m_header_2.number_of_raw_data_entries);
|
||||||
|
m_raw_data_entries.resize(number_of_raw_data_entries);
|
||||||
|
if (!m_file.Seek(Common::swap64(m_header_2.raw_data_entries_offset), SEEK_SET))
|
||||||
|
return false;
|
||||||
|
if (!m_file.ReadArray(m_raw_data_entries.data(), number_of_raw_data_entries))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::sort(m_raw_data_entries.begin(), m_raw_data_entries.end(),
|
||||||
|
[](const RawDataEntry& a, const RawDataEntry& b) {
|
||||||
|
return Common::swap64(a.data_offset) < Common::swap64(b.data_offset);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Compression
|
||||||
|
const u32 number_of_group_entries = Common::swap32(m_header_2.number_of_group_entries);
|
||||||
|
m_group_entries.resize(number_of_group_entries);
|
||||||
|
if (!m_file.Seek(Common::swap64(m_header_2.group_entries_offset), SEEK_SET))
|
||||||
|
return false;
|
||||||
|
if (!m_file.ReadArray(m_group_entries.data(), number_of_group_entries))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +145,64 @@ std::unique_ptr<WIAFileReader> WIAFileReader::Create(File::IOFile file, const st
|
||||||
|
|
||||||
bool WIAFileReader::Read(u64 offset, u64 size, u8* out_ptr)
|
bool WIAFileReader::Read(u64 offset, u64 size, u8* out_ptr)
|
||||||
{
|
{
|
||||||
if (offset + size <= sizeof(WIAHeader2::disc_header))
|
if (offset + size > Common::swap64(m_header_1.iso_file_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (offset < sizeof(WIAHeader2::disc_header))
|
||||||
{
|
{
|
||||||
std::memcpy(out_ptr, m_header_2.disc_header.data() + offset, size);
|
const u64 bytes_to_read = std::min(sizeof(WIAHeader2::disc_header) - offset, size);
|
||||||
return true;
|
std::memcpy(out_ptr, m_header_2.disc_header.data() + offset, bytes_to_read);
|
||||||
|
offset += bytes_to_read;
|
||||||
|
size -= bytes_to_read;
|
||||||
|
out_ptr += bytes_to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not implemented
|
const u32 chunk_size = Common::swap32(m_header_2.chunk_size);
|
||||||
return false;
|
for (RawDataEntry raw_data : m_raw_data_entries)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
u64 data_offset = Common::swap64(raw_data.data_offset);
|
||||||
|
u64 data_size = Common::swap64(raw_data.data_size);
|
||||||
|
|
||||||
|
if (data_offset + data_size <= offset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (offset < data_offset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const u64 skipped_data = data_offset % VolumeWii::BLOCK_TOTAL_SIZE;
|
||||||
|
data_offset -= skipped_data;
|
||||||
|
data_size += skipped_data;
|
||||||
|
|
||||||
|
const u32 number_of_groups = Common::swap32(raw_data.number_of_groups);
|
||||||
|
const u64 group_index = (offset - data_offset) / chunk_size;
|
||||||
|
for (u64 i = group_index; i < number_of_groups && size > 0; ++i)
|
||||||
|
{
|
||||||
|
const u64 total_group_index = Common::swap32(raw_data.group_index) + i;
|
||||||
|
if (total_group_index >= m_group_entries.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const GroupEntry group = m_group_entries[total_group_index];
|
||||||
|
const u64 group_offset_on_disc = data_offset + i * chunk_size;
|
||||||
|
const u64 offset_in_group = offset - group_offset_on_disc;
|
||||||
|
|
||||||
|
// TODO: Compression
|
||||||
|
|
||||||
|
const u64 group_offset_in_file = static_cast<u64>(Common::swap32(group.data_offset)) << 2;
|
||||||
|
const u64 offset_in_file = group_offset_in_file + offset_in_group;
|
||||||
|
const u64 bytes_to_read = std::min(chunk_size - offset_in_group, size);
|
||||||
|
if (!m_file.Seek(offset_in_file, SEEK_SET) || !m_file.ReadBytes(out_ptr, bytes_to_read))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
offset += bytes_to_read;
|
||||||
|
size -= bytes_to_read;
|
||||||
|
out_ptr += bytes_to_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WIAFileReader::VersionToString(u32 version)
|
std::string WIAFileReader::VersionToString(u32 version)
|
||||||
|
|
|
@ -41,6 +41,7 @@ private:
|
||||||
static std::string VersionToString(u32 version);
|
static std::string VersionToString(u32 version);
|
||||||
|
|
||||||
using SHA1 = std::array<u8, 20>;
|
using SHA1 = std::array<u8, 20>;
|
||||||
|
using WiiKey = std::array<u8, 16>;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct WIAHeader1
|
struct WIAHeader1
|
||||||
|
@ -54,10 +55,8 @@ private:
|
||||||
u64 wia_file_size;
|
u64 wia_file_size;
|
||||||
SHA1 header_1_hash;
|
SHA1 header_1_hash;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
|
||||||
static_assert(sizeof(WIAHeader1) == 0x48, "Wrong size for WIA header 1");
|
static_assert(sizeof(WIAHeader1) == 0x48, "Wrong size for WIA header 1");
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct WIAHeader2
|
struct WIAHeader2
|
||||||
{
|
{
|
||||||
u32 disc_type;
|
u32 disc_type;
|
||||||
|
@ -67,7 +66,7 @@ private:
|
||||||
|
|
||||||
std::array<u8, 0x80> disc_header;
|
std::array<u8, 0x80> disc_header;
|
||||||
|
|
||||||
u32 number_of_partitions_entries;
|
u32 number_of_partition_entries;
|
||||||
u32 partition_entry_size;
|
u32 partition_entry_size;
|
||||||
u64 partition_entries_offset;
|
u64 partition_entries_offset;
|
||||||
SHA1 partition_entries_hash;
|
SHA1 partition_entries_hash;
|
||||||
|
@ -79,9 +78,51 @@ private:
|
||||||
u32 number_of_group_entries;
|
u32 number_of_group_entries;
|
||||||
u64 group_entries_offset;
|
u64 group_entries_offset;
|
||||||
u32 group_entries_size;
|
u32 group_entries_size;
|
||||||
|
|
||||||
|
u8 compressor_data_size;
|
||||||
|
u8 compressor_data[7];
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(WIAHeader2) == 0xdc, "Wrong size for WIA header 2");
|
||||||
|
|
||||||
|
struct PartitionDataEntry
|
||||||
|
{
|
||||||
|
u32 first_sector;
|
||||||
|
u32 number_of_sectors;
|
||||||
|
u32 group_index;
|
||||||
|
u32 number_of_groups;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PartitionDataEntry) == 0x10, "Wrong size for WIA partition data entry");
|
||||||
|
|
||||||
|
struct PartitionEntry
|
||||||
|
{
|
||||||
|
WiiKey partition_key;
|
||||||
|
std::array<PartitionDataEntry, 2> data_entries;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PartitionEntry) == 0x30, "Wrong size for WIA partition entry");
|
||||||
|
|
||||||
|
struct RawDataEntry
|
||||||
|
{
|
||||||
|
u64 data_offset;
|
||||||
|
u64 data_size;
|
||||||
|
u32 group_index;
|
||||||
|
u32 number_of_groups;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(RawDataEntry) == 0x18, "Wrong size for WIA raw data entry");
|
||||||
|
|
||||||
|
struct GroupEntry
|
||||||
|
{
|
||||||
|
u32 data_offset; // >> 2
|
||||||
|
u32 data_size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GroupEntry) == 0x08, "Wrong size for WIA group entry");
|
||||||
|
|
||||||
|
struct HashExceptionEntry
|
||||||
|
{
|
||||||
|
u16 offset;
|
||||||
|
SHA1 hash;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(HashExceptionEntry) == 0x16, "Wrong size for WIA hash exception entry");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
static_assert(sizeof(WIAHeader2) == 0xd4, "Wrong size for WIA header 2");
|
|
||||||
|
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
|
||||||
|
@ -89,6 +130,9 @@ private:
|
||||||
|
|
||||||
WIAHeader1 m_header_1;
|
WIAHeader1 m_header_1;
|
||||||
WIAHeader2 m_header_2;
|
WIAHeader2 m_header_2;
|
||||||
|
std::vector<PartitionEntry> m_partition_entries;
|
||||||
|
std::vector<RawDataEntry> m_raw_data_entries;
|
||||||
|
std::vector<GroupEntry> m_group_entries;
|
||||||
|
|
||||||
static constexpr u32 WIA_VERSION = 0x01000000;
|
static constexpr u32 WIA_VERSION = 0x01000000;
|
||||||
static constexpr u32 WIA_VERSION_WRITE_COMPATIBLE = 0x01000000;
|
static constexpr u32 WIA_VERSION_WRITE_COMPATIBLE = 0x01000000;
|
||||||
|
|
Loading…
Reference in New Issue