bool CNANDContentLoader::Initialize(const std::string& name) { if (name.empty()) return false; m_Path = name; WiiWAD wad(name); std::vector<u8> data_app; std::vector<u8> tmd; std::vector<u8> decrypted_title_key; if (wad.IsValid()) { m_IsWAD = true; m_Ticket = wad.GetTicket(); decrypted_title_key = GetKeyFromTicket(m_Ticket); tmd = wad.GetTMD(); data_app = wad.GetDataApp(); } else { std::string tmd_filename(m_Path); if (tmd_filename.back() == '/') tmd_filename += "title.tmd"; else m_Path = tmd_filename.substr(0, tmd_filename.find("title.tmd")); File::IOFile tmd_file(tmd_filename, "rb"); if (!tmd_file) { WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s", tmd_filename.c_str()); return false; } tmd.resize(static_cast<size_t>(File::GetSize(tmd_filename))); tmd_file.ReadBytes(tmd.data(), tmd.size()); } std::copy(&tmd[0], &tmd[TMD_HEADER_SIZE], m_TMDHeader); std::copy(&tmd[0x180], &tmd[0x180 + TMD_VIEW_SIZE], m_TMDView); m_TitleVersion = Common::swap16(&tmd[0x01DC]); m_NumEntries = Common::swap16(&tmd[0x01DE]); m_BootIndex = Common::swap16(&tmd[0x01E0]); m_TitleID = Common::swap64(&tmd[0x018C]); m_IosVersion = Common::swap16(&tmd[0x018A]); m_Country = static_cast<u8>(m_TitleID & 0xFF); if (m_Country == 2) // SYSMENU m_Country = GetSysMenuRegion(m_TitleVersion); InitializeContentEntries(tmd, decrypted_title_key, data_app); return true; }
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; }