// Copyright (C) 2003 Dolphin Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ #include "stdafx.h" #include "NANDContentLoader.h" #include #include #include "AES/aes.h" #include "MathUtil.h" #include "FileUtil.h" #include "Log.h" #include "WiiWad.h" namespace DiscIO { CSharedContent CSharedContent::m_Instance; cUIDsys cUIDsys::m_Instance; CSharedContent::CSharedContent() { lastID = 0; sprintf(contentMap, "%sshared1/content.map", File::GetUserPath(D_WIIUSER_IDX)); if (File::Exists(contentMap)) { FILE* pFile = fopen(contentMap, "rb"); while(!feof(pFile)) { SElement Element; if (fread(&Element, sizeof(SElement), 1, pFile) == 1) { m_Elements.push_back(Element); lastID++; } } fclose(pFile); } else { File::CreateFullPath(contentMap); } } CSharedContent::~CSharedContent() {} std::string CSharedContent::GetFilenameFromSHA1(u8* _pHash) { for (size_t i=0; i& GetContent() const { return m_Content; } const u16 GetTitleVersion() const {return m_TileVersion;} const u16 GetNumEntries() const {return m_numEntries;} const DiscIO::IVolume::ECountry GetCountry() const; private: bool m_Valid; u64 m_TitleID; u16 m_IosVersion; u32 m_BootIndex; u16 m_numEntries; u16 m_TileVersion; u8 m_TicketView[TICKET_VIEW_SIZE]; u8 m_TmdHeader[TMD_HEADER_SIZE]; std::vector m_Content; bool CreateFromDirectory(const std::string& _rPath); bool CreateFromWAD(const std::string& _rName); void AESDecode(u8* _pKey, u8* _IV, u8* _pSrc, u32 _Size, u8* _pDest); void GetKeyFromTicket(u8* pTicket, u8* pTicketKey); bool ParseTMD(u8* pDataApp, u32 pDataAppSize, u8* pTicket, u8* pTMD); }; CNANDContentLoader::CNANDContentLoader(const std::string& _rName) : m_Valid(false) , m_TitleID(-1) , m_IosVersion(0x09) , m_BootIndex(-1) { if (File::IsDirectory(_rName.c_str())) { m_Valid = CreateFromDirectory(_rName); } else if (File::Exists(_rName.c_str())) { m_Valid = CreateFromWAD(_rName); } else { // _dbg_assert_msg_(BOOT, 0, "CNANDContentLoader loads neither folder nor file"); } } CNANDContentLoader::~CNANDContentLoader() { for (size_t i=0; isecond; itr++; } m_Map.clear(); } const INANDContentLoader& CNANDContentManager::GetNANDLoader(const std::string& _rName) { CNANDContentMap::iterator lb = m_Map.lower_bound(_rName); if(lb == m_Map.end() || (m_Map.key_comp()(_rName, lb->first))) m_Map.insert(lb, CNANDContentMap::value_type(_rName, new CNANDContentLoader(_rName))); return *m_Map[_rName]; } cUIDsys::cUIDsys() { sprintf(uidSys, "%ssys/uid.sys", File::GetUserPath(D_WIIUSER_IDX)); lastUID = 0x00001000; bool validTMD; bool validTIK; if (File::Exists(uidSys)) { FILE* pFile = fopen(uidSys, "rb"); while(!feof(pFile)) { SElement Element; if (fread(&Element, sizeof(SElement), 1, pFile) == 1) { validTMD = CheckTitleTMD(Common::swap64(Element.titleID)); validTIK = CheckTitleTIK(Common::swap64(Element.titleID)); if (validTMD && validTIK) { *(u32*)&(Element.UID) = Common::swap32(lastUID++); m_Elements.push_back(Element); } } } fclose(pFile); } else { SElement Element; *(u64*)&(Element.titleID) = Common::swap64(0x0000000100000002ull); *(u32*)&(Element.UID) = Common::swap32(lastUID++); File::CreateFullPath(uidSys); FILE* pFile = fopen(uidSys, "wb"); if (pFile) { if (fwrite(&Element, sizeof(SElement), 1, pFile) != 1) ERROR_LOG(DISCIO, "fwrite failed"); fclose(pFile); } } } cUIDsys::~cUIDsys() {} u32 cUIDsys::GetUIDFromTitle(u64 _Title) { for (size_t i=0; i& _TitleIDs) { for (size_t i = 0; i < m_Elements.size(); i++) { _TitleIDs.push_back(Common::swap64(m_Elements[i].titleID)); } } bool cUIDsys::CheckTitleTMD(u64 _TitleID) { char TitlePath[1024]; sprintf(TitlePath, "%stitle/%08x/%08x/content/title.tmd", File::GetUserPath(D_WIIUSER_IDX), (u32)(_TitleID >> 32), (u32)(_TitleID & 0xFFFFFFFF)); if (File::Exists(TitlePath)) { FILE* pTMDFile = fopen(TitlePath, "rb"); if(pTMDFile) { u64 TitleID = 0xDEADBEEFDEADBEEFULL; fseek(pTMDFile, 0x18C, SEEK_SET); fread(&TitleID, 8, 1, pTMDFile); fclose(pTMDFile); if (_TitleID == Common::swap64(TitleID)) return true; } } INFO_LOG(DISCIO, "Invalid or no tmd for title %08x %08x", (u32)(_TitleID >> 32), (u32)(_TitleID & 0xFFFFFFFF)); return false; } bool cUIDsys::CheckTitleTIK(u64 _TitleID) { char TitlePath[1024]; sprintf(TitlePath, "%sticket/%08x/%08x.tik", File::GetUserPath(D_WIIUSER_IDX), (u32)(_TitleID >> 32), (u32)(_TitleID & 0xFFFFFFFF)); if (File::Exists(TitlePath)) { FILE* pTIKFile = fopen(TitlePath, "rb"); if(pTIKFile) { u64 TitleID = 0xDEADBEEFDEADBEEFULL; fseek(pTIKFile, 0x1dC, SEEK_SET); fread(&TitleID, 8, 1, pTIKFile); fclose(pTIKFile); if (_TitleID == Common::swap64(TitleID)) return true; } } INFO_LOG(DISCIO, "Invalid or no tik for title %08x %08x", (u32)(_TitleID >> 32), (u32)(_TitleID & 0xFFFFFFFF)); return false; } } // namespace end