// Copyright 2009 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include #include #include "Common/Align.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/WiiWad.h" namespace DiscIO { namespace { std::vector CreateWADEntry(IBlobReader& reader, u32 size, u64 offset) { if (size == 0) return {}; std::vector buffer(size); if (!reader.Read(offset, size, buffer.data())) { ERROR_LOG(DISCIO, "WiiWAD: Could not read from file"); PanicAlertT("WiiWAD: Could not read from file"); } return buffer; } bool IsWiiWAD(const CBlobBigEndianReader& reader) { u32 header_size = 0; u32 header_type = 0; reader.ReadSwapped(0x0, &header_size); reader.ReadSwapped(0x4, &header_type); return header_size == 0x20 && (header_type == 0x49730000 || header_type == 0x69620000); } } // Anonymous namespace WiiWAD::WiiWAD(const std::string& name) : m_reader(CreateBlobReader(name)) { if (m_reader == nullptr || File::IsDirectory(name)) { m_valid = false; return; } m_valid = ParseWAD(); } WiiWAD::~WiiWAD() { } bool WiiWAD::ParseWAD() { CBlobBigEndianReader big_endian_reader(*m_reader); if (!IsWiiWAD(big_endian_reader)) return false; u32 certificate_chain_size; u32 reserved; u32 ticket_size; u32 tmd_size; u32 data_app_size; u32 footer_size; if (!big_endian_reader.ReadSwapped(0x08, &certificate_chain_size) || !big_endian_reader.ReadSwapped(0x0C, &reserved) || !big_endian_reader.ReadSwapped(0x10, &ticket_size) || !big_endian_reader.ReadSwapped(0x14, &tmd_size) || !big_endian_reader.ReadSwapped(0x18, &data_app_size) || !big_endian_reader.ReadSwapped(0x1C, &footer_size)) return false; if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) _dbg_assert_msg_(BOOT, reserved == 0x00, "WiiWAD: Reserved must be 0x00"); u32 offset = 0x40; m_certificate_chain = CreateWADEntry(*m_reader, certificate_chain_size, offset); offset += Common::AlignUp(certificate_chain_size, 0x40); m_ticket.SetBytes(CreateWADEntry(*m_reader, ticket_size, offset)); offset += Common::AlignUp(ticket_size, 0x40); m_tmd.SetBytes(CreateWADEntry(*m_reader, tmd_size, offset)); offset += Common::AlignUp(tmd_size, 0x40); m_data_app_offset = offset; m_data_app = CreateWADEntry(*m_reader, data_app_size, offset); offset += Common::AlignUp(data_app_size, 0x40); m_footer = CreateWADEntry(*m_reader, footer_size, offset); offset += Common::AlignUp(footer_size, 0x40); return true; } std::vector WiiWAD::GetContent(u16 index) const { u64 offset = m_data_app_offset; for (const IOS::ES::Content& content : m_tmd.GetContents()) { const u64 aligned_size = Common::AlignUp(content.size, 0x40); if (content.index == index) { std::vector data(aligned_size); if (!m_reader->Read(offset, aligned_size, data.data())) return {}; return data; } offset += aligned_size; } return {}; } } // namespace DiscIO