bool CNANDContentLoader::Initialize(const std::string& _rName) { if (_rName.empty()) return false; m_Path = _rName; WiiWAD Wad(_rName); u8* pDataApp = nullptr; u8* pTMD = nullptr; u8 DecryptTitleKey[16]; u8 IV[16]; if (Wad.IsValid()) { m_isWAD = true; m_TIKSize = Wad.GetTicketSize(); m_TIK = new u8[m_TIKSize]; memcpy(m_TIK, Wad.GetTicket(), m_TIKSize); GetKeyFromTicket(m_TIK, DecryptTitleKey); u32 pTMDSize = Wad.GetTMDSize(); pTMD = new u8[pTMDSize]; memcpy(pTMD, Wad.GetTMD(), pTMDSize); pDataApp = Wad.GetDataApp(); } else { std::string TMDFileName(m_Path); if ('/' == *TMDFileName.rbegin()) TMDFileName += "title.tmd"; else m_Path = TMDFileName.substr(0, TMDFileName.find("title.tmd")); File::IOFile pTMDFile(TMDFileName, "rb"); if (!pTMDFile) { WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s", TMDFileName.c_str()); return false; } u32 pTMDSize = (u32)File::GetSize(TMDFileName); pTMD = new u8[pTMDSize]; pTMDFile.ReadBytes(pTMD, (size_t)pTMDSize); pTMDFile.Close(); } memcpy(m_TMDView, pTMD + 0x180, TMD_VIEW_SIZE); memcpy(m_TMDHeader, pTMD, TMD_HEADER_SIZE); m_TitleVersion = Common::swap16(pTMD + 0x01dc); m_numEntries = Common::swap16(pTMD + 0x01de); m_BootIndex = Common::swap16(pTMD + 0x01e0); m_TitleID = Common::swap64(pTMD + 0x018c); m_IosVersion = Common::swap16(pTMD + 0x018a); m_Country = *(u8*)&m_TitleID; if (m_Country == 2) // SYSMENU m_Country = GetSysMenuRegion(m_TitleVersion); m_Content.resize(m_numEntries); for (u32 i=0; i<m_numEntries; i++) { SNANDContent& rContent = m_Content[i]; rContent.m_ContentID = Common::swap32(pTMD + 0x01e4 + 0x24*i); rContent.m_Index = Common::swap16(pTMD + 0x01e8 + 0x24*i); rContent.m_Type = Common::swap16(pTMD + 0x01ea + 0x24*i); rContent.m_Size= (u32)Common::swap64(pTMD + 0x01ec + 0x24*i); memcpy(rContent.m_SHA1Hash, pTMD + 0x01f4 + 0x24*i, 20); memcpy(rContent.m_Header, pTMD + 0x01e4 + 0x24*i, 36); if (m_isWAD) { u32 RoundedSize = ROUND_UP(rContent.m_Size, 0x40); rContent.m_pData = new u8[RoundedSize]; memset(IV, 0, sizeof IV); memcpy(IV, pTMD + 0x01e8 + 0x24*i, 2); AESDecode(DecryptTitleKey, IV, pDataApp, RoundedSize, rContent.m_pData); pDataApp += RoundedSize; continue; } rContent.m_pData = nullptr; if (rContent.m_Type & 0x8000) // shared app { rContent.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(rContent.m_SHA1Hash); } else { rContent.m_Filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), rContent.m_ContentID); } // Be graceful about incorrect tmds. if (File::Exists(rContent.m_Filename)) { rContent.m_Size = (u32) File::GetSize(rContent.m_Filename); } } delete [] pTMD; return true; }
#include "TestDefines.h" TEST_CASE("Nominals") { Wad wad = Nominals::rub(); REQUIRE(wad == Wad({ RUB_10, RUB_50, RUB_100, RUB_500, RUB_1000, RUB_5000 })); }