mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #3736 from BhaaLseN/issue-9135
Rewrite NAND Content handling in ES to fix Issue 9135
This commit is contained in:
@ -101,15 +101,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
|
|||||||
|
|
||||||
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
|
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
|
||||||
|
|
||||||
std::unique_ptr<CDolLoader> pDolLoader;
|
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
|
||||||
if (pContent->m_data.empty())
|
|
||||||
{
|
|
||||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
|
|
||||||
}
|
|
||||||
if (!pDolLoader->IsValid())
|
if (!pDolLoader->IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@ std::string CWII_IPC_HLE_Device_es::m_ContentFile;
|
|||||||
|
|
||||||
CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
|
CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
, m_pContentLoader(nullptr)
|
|
||||||
, m_TitleID(-1)
|
, m_TitleID(-1)
|
||||||
, m_AccessIdentID(0x6000000)
|
, m_AccessIdentID(0x6000000)
|
||||||
{
|
{
|
||||||
@ -99,12 +98,12 @@ void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile)
|
|||||||
|
|
||||||
void CWII_IPC_HLE_Device_es::OpenInternal()
|
void CWII_IPC_HLE_Device_es::OpenInternal()
|
||||||
{
|
{
|
||||||
m_pContentLoader = &DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
|
auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
|
||||||
|
|
||||||
// check for cd ...
|
// check for cd ...
|
||||||
if (m_pContentLoader->IsValid())
|
if (contentLoader.IsValid())
|
||||||
{
|
{
|
||||||
m_TitleID = m_pContentLoader->GetTitleID();
|
m_TitleID = contentLoader.GetTitleID();
|
||||||
|
|
||||||
m_TitleIDs.clear();
|
m_TitleIDs.clear();
|
||||||
DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs);
|
DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs);
|
||||||
@ -164,7 +163,7 @@ void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
|
|||||||
SContentAccess& Access = pair.second;
|
SContentAccess& Access = pair.second;
|
||||||
Position = Access.m_Position;
|
Position = Access.m_Position;
|
||||||
TitleID = Access.m_TitleID;
|
TitleID = Access.m_TitleID;
|
||||||
Index = Access.m_pContent->m_Index;
|
Index = Access.m_Index;
|
||||||
p.Do(CFD);
|
p.Do(CFD);
|
||||||
p.Do(Position);
|
p.Do(Position);
|
||||||
p.Do(TitleID);
|
p.Do(TitleID);
|
||||||
@ -186,14 +185,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
|
|||||||
|
|
||||||
IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
|
IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce)
|
||||||
{
|
{
|
||||||
// Leave deletion of the CNANDContentLoader objects to CNANDContentManager, don't do it here!
|
|
||||||
m_NANDContent.clear();
|
|
||||||
for (auto& pair : m_ContentAccessMap)
|
|
||||||
{
|
|
||||||
delete pair.second.m_pFile;
|
|
||||||
}
|
|
||||||
m_ContentAccessMap.clear();
|
m_ContentAccessMap.clear();
|
||||||
m_pContentLoader = nullptr;
|
|
||||||
m_TitleIDs.clear();
|
m_TitleIDs.clear();
|
||||||
m_TitleID = -1;
|
m_TitleID = -1;
|
||||||
m_AccessIdentID = 0x6000000;
|
m_AccessIdentID = 0x6000000;
|
||||||
@ -202,6 +194,8 @@ IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce
|
|||||||
if (!_bForce)
|
if (!_bForce)
|
||||||
Memory::Write_U32(0, _CommandAddress + 4);
|
Memory::Write_U32(0, _CommandAddress + 4);
|
||||||
m_Active = false;
|
m_Active = false;
|
||||||
|
// clear the NAND content cache to make sure nothing remains open.
|
||||||
|
DiscIO::CNANDContentManager::Access().ClearCache();
|
||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,22 +218,11 @@ u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
|
|||||||
|
|
||||||
SContentAccess Access;
|
SContentAccess Access;
|
||||||
Access.m_Position = 0;
|
Access.m_Position = 0;
|
||||||
Access.m_pContent = pContent;
|
Access.m_Index = pContent->m_Index;
|
||||||
|
Access.m_Size = pContent->m_Size;
|
||||||
Access.m_TitleID = TitleID;
|
Access.m_TitleID = TitleID;
|
||||||
Access.m_pFile = nullptr;
|
|
||||||
|
|
||||||
if (pContent->m_data.empty())
|
pContent->m_Data->Open();
|
||||||
{
|
|
||||||
std::string Filename = pContent->m_Filename;
|
|
||||||
INFO_LOG(WII_IPC_ES, "ES: load %s", Filename.c_str());
|
|
||||||
|
|
||||||
Access.m_pFile = new File::IOFile(Filename, "rb");
|
|
||||||
if (!Access.m_pFile->IsGood())
|
|
||||||
{
|
|
||||||
WARN_LOG(WII_IPC_ES, "ES: couldn't load %s", Filename.c_str());
|
|
||||||
return 0xffffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ContentAccessMap[CFD] = Access;
|
m_ContentAccessMap[CFD] = Access;
|
||||||
return CFD;
|
return CFD;
|
||||||
@ -323,21 +306,21 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
|
|
||||||
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
|
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
|
const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
|
||||||
if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
|
if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
|
||||||
{
|
{
|
||||||
for (u16 i = 0; i < rNANDCOntent.GetNumEntries(); i++)
|
for (u16 i = 0; i < rNANDContent.GetNumEntries(); i++)
|
||||||
{
|
{
|
||||||
Memory::Write_U32(rNANDCOntent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
|
Memory::Write_U32(rNANDContent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4);
|
||||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDCOntent.GetContentByIndex(i)->m_ContentID);
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDContent.GetContentByIndex(i)->m_ContentID);
|
||||||
}
|
}
|
||||||
Memory::Write_U32(0, _CommandAddress + 0x4);
|
Memory::Write_U32(0, _CommandAddress + 0x4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
|
Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
|
||||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu",
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu",
|
||||||
rNANDCOntent.GetContentSize());
|
rNANDContent.GetContentSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
@ -395,32 +378,22 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
|
|
||||||
u8* pDest = Memory::GetPointer(Addr);
|
u8* pDest = Memory::GetPointer(Addr);
|
||||||
|
|
||||||
if (rContent.m_Position + Size > rContent.m_pContent->m_Size)
|
if (rContent.m_Position + Size > rContent.m_Size)
|
||||||
{
|
{
|
||||||
Size = rContent.m_pContent->m_Size-rContent.m_Position;
|
Size = rContent.m_Size - rContent.m_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Size > 0)
|
if (Size > 0)
|
||||||
{
|
{
|
||||||
if (pDest)
|
if (pDest)
|
||||||
{
|
{
|
||||||
if (rContent.m_pContent->m_data.empty())
|
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID);
|
||||||
|
// ContentLoader should never be invalid; rContent has been created by it.
|
||||||
|
if (ContentLoader.IsValid())
|
||||||
{
|
{
|
||||||
auto& pFile = rContent.m_pFile;
|
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index);
|
||||||
if (!pFile->Seek(rContent.m_Position, SEEK_SET))
|
if (!pContent->m_Data->GetRange(rContent.m_Position, Size, pDest))
|
||||||
{
|
ERROR_LOG(WII_IPC_ES, "ES: failed to read %u bytes from %u!", Size, rContent.m_Position);
|
||||||
ERROR_LOG(WII_IPC_ES, "ES: couldn't seek!");
|
|
||||||
}
|
|
||||||
WARN_LOG(WII_IPC_ES, "2 %p", pFile->GetHandle());
|
|
||||||
if (!pFile->ReadBytes(pDest, Size))
|
|
||||||
{
|
|
||||||
ERROR_LOG(WII_IPC_ES, "ES: short read; returning uninitialized data!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const u8* src = &rContent.m_pContent->m_data[rContent.m_Position];
|
|
||||||
memcpy(pDest, src, Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rContent.m_Position += Size;
|
rContent.m_Position += Size;
|
||||||
@ -431,7 +404,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->m_Index);
|
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_Index);
|
||||||
|
|
||||||
Memory::Write_U32(Size, _CommandAddress + 0x4);
|
Memory::Write_U32(Size, _CommandAddress + 0x4);
|
||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
@ -454,7 +427,14 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete itr->second.m_pFile;
|
const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(itr->second.m_TitleID);
|
||||||
|
// ContentLoader should never be invalid; we shouldn't be here if ES_OPENCONTENT failed before.
|
||||||
|
if (ContentLoader.IsValid())
|
||||||
|
{
|
||||||
|
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(itr->second.m_Index);
|
||||||
|
pContent->m_Data->Close();
|
||||||
|
}
|
||||||
|
|
||||||
m_ContentAccessMap.erase(itr);
|
m_ContentAccessMap.erase(itr);
|
||||||
|
|
||||||
Memory::Write_U32(0, _CommandAddress + 0x4);
|
Memory::Write_U32(0, _CommandAddress + 0x4);
|
||||||
@ -490,7 +470,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // END
|
case 2: // END
|
||||||
rContent.m_Position = rContent.m_pContent->m_Size + Addr;
|
rContent.m_Position = rContent.m_Size + Addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,6 +886,11 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
|
u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16);
|
||||||
u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
|
u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24);
|
||||||
|
|
||||||
|
// ES_LAUNCH should probably reset thw whole state, which at least means closing all open files.
|
||||||
|
// leaving them open through ES_LAUNCH may cause hangs and other funky behavior
|
||||||
|
// (supposedly when trying to re-open those files).
|
||||||
|
DiscIO::CNANDContentManager::Access().ClearCache();
|
||||||
|
|
||||||
std::string tContentFile;
|
std::string tContentFile;
|
||||||
if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU)
|
if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU)
|
||||||
{
|
{
|
||||||
@ -917,15 +902,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
if (pContent)
|
if (pContent)
|
||||||
{
|
{
|
||||||
tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT);
|
tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT);
|
||||||
std::unique_ptr<CDolLoader> pDolLoader;
|
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
|
||||||
if (pContent->m_data.empty())
|
|
||||||
{
|
|
||||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pDolLoader->IsValid())
|
if (pDolLoader->IsValid())
|
||||||
{
|
{
|
||||||
@ -1077,31 +1054,17 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||||||
return GetDefaultReply();
|
return GetDefaultReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This cache is redundant with the one in CNANDContentManager.h
|
const DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 title_id)
|
||||||
const DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 _TitleID)
|
|
||||||
{
|
{
|
||||||
if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
|
// for WADs, the passed title id and the stored title id match; along with m_ContentFile being set to the
|
||||||
return *m_pContentLoader;
|
// actual WAD file name. We cannot simply get a NAND Loader for the title id in those cases, since the WAD
|
||||||
|
// need not be installed in the NAND, but it could be opened directly from a WAD file anywhere on disk.
|
||||||
|
if (m_TitleID == title_id && !m_ContentFile.empty())
|
||||||
|
return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile);
|
||||||
|
|
||||||
CTitleToContentMap::iterator itr = m_NANDContent.find(_TitleID);
|
return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT);
|
||||||
if (itr != m_NANDContent.end())
|
|
||||||
return *itr->second;
|
|
||||||
|
|
||||||
m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID, Common::FROM_SESSION_ROOT);
|
|
||||||
|
|
||||||
_dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
|
|
||||||
return *m_NANDContent[_TitleID];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_es::IsValid(u64 _TitleID) const
|
|
||||||
{
|
|
||||||
if (m_pContentLoader->IsValid() && m_pContentLoader->GetTitleID() == _TitleID)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector<u8>& tmd)
|
u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector<u8>& tmd)
|
||||||
{
|
{
|
||||||
u64 title_id = 0xDEADBEEFDEADBEEFull;
|
u64 title_id = 0xDEADBEEFDEADBEEFull;
|
||||||
@ -1168,6 +1131,8 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector<u8>& tmd)
|
|||||||
ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND.");
|
ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND.");
|
||||||
}
|
}
|
||||||
DiscIO::cUIDsys::AccessInstance().AddTitle(tmd_title_id);
|
DiscIO::cUIDsys::AccessInstance().AddTitle(tmd_title_id);
|
||||||
|
// DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager.
|
||||||
|
// clear the cache to avoid content access mismatches.
|
||||||
DiscIO::CNANDContentManager::Access().ClearCache();
|
DiscIO::CNANDContentManager::Access().ClearCache();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -125,30 +125,22 @@ private:
|
|||||||
{
|
{
|
||||||
u32 m_Position;
|
u32 m_Position;
|
||||||
u64 m_TitleID;
|
u64 m_TitleID;
|
||||||
const DiscIO::SNANDContent* m_pContent;
|
u16 m_Index;
|
||||||
// This is a (raw) pointer to work around a MSVC bug.
|
u32 m_Size;
|
||||||
File::IOFile* m_pFile;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<u32, SContentAccess> CContentAccessMap;
|
typedef std::map<u32, SContentAccess> CContentAccessMap;
|
||||||
CContentAccessMap m_ContentAccessMap;
|
CContentAccessMap m_ContentAccessMap;
|
||||||
|
|
||||||
typedef std::map<u64, const DiscIO::CNANDContentLoader*> CTitleToContentMap;
|
|
||||||
CTitleToContentMap m_NANDContent;
|
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader* m_pContentLoader;
|
|
||||||
|
|
||||||
std::vector<u64> m_TitleIDs;
|
std::vector<u64> m_TitleIDs;
|
||||||
u64 m_TitleID;
|
u64 m_TitleID;
|
||||||
u32 m_AccessIdentID;
|
u32 m_AccessIdentID;
|
||||||
|
|
||||||
static u8 *keyTable[11];
|
static u8 *keyTable[11];
|
||||||
|
|
||||||
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 _TitleID);
|
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
|
||||||
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
||||||
|
|
||||||
bool IsValid(u64 _TitleID) const;
|
|
||||||
|
|
||||||
struct ecc_cert_t
|
struct ecc_cert_t
|
||||||
{
|
{
|
||||||
u32 sig_type ;
|
u32 sig_type ;
|
||||||
|
@ -38,26 +38,26 @@ CSharedContent::CSharedContent()
|
|||||||
void CSharedContent::UpdateLocation()
|
void CSharedContent::UpdateLocation()
|
||||||
{
|
{
|
||||||
m_Elements.clear();
|
m_Elements.clear();
|
||||||
m_lastID = 0;
|
m_LastID = 0;
|
||||||
m_contentMap = StringFromFormat("%s/shared1/content.map", File::GetUserPath(D_WIIROOT_IDX).c_str());
|
m_ContentMap = StringFromFormat("%s/shared1/content.map", File::GetUserPath(D_WIIROOT_IDX).c_str());
|
||||||
|
|
||||||
File::IOFile pFile(m_contentMap, "rb");
|
File::IOFile pFile(m_ContentMap, "rb");
|
||||||
SElement Element;
|
SElement Element;
|
||||||
while (pFile.ReadArray(&Element, 1))
|
while (pFile.ReadArray(&Element, 1))
|
||||||
{
|
{
|
||||||
m_Elements.push_back(Element);
|
m_Elements.push_back(Element);
|
||||||
m_lastID++;
|
m_LastID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSharedContent::~CSharedContent()
|
CSharedContent::~CSharedContent()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string CSharedContent::GetFilenameFromSHA1(const u8* _pHash)
|
std::string CSharedContent::GetFilenameFromSHA1(const u8* hash)
|
||||||
{
|
{
|
||||||
for (auto& Element : m_Elements)
|
for (auto& Element : m_Elements)
|
||||||
{
|
{
|
||||||
if (memcmp(_pHash, Element.SHA1Hash, 20) == 0)
|
if (memcmp(hash, Element.SHA1Hash, 20) == 0)
|
||||||
{
|
{
|
||||||
return StringFromFormat("%s/shared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIROOT_IDX).c_str(),
|
return StringFromFormat("%s/shared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIROOT_IDX).c_str(),
|
||||||
Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3],
|
Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3],
|
||||||
@ -67,39 +67,94 @@ std::string CSharedContent::GetFilenameFromSHA1(const u8* _pHash)
|
|||||||
return "unk";
|
return "unk";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CSharedContent::AddSharedContent(const u8* _pHash)
|
std::string CSharedContent::AddSharedContent(const u8* hash)
|
||||||
{
|
{
|
||||||
std::string filename = GetFilenameFromSHA1(_pHash);
|
std::string filename = GetFilenameFromSHA1(hash);
|
||||||
|
|
||||||
if (strcasecmp(filename.c_str(), "unk") == 0)
|
if (strcasecmp(filename.c_str(), "unk") == 0)
|
||||||
{
|
{
|
||||||
std::string id = StringFromFormat("%08x", m_lastID);
|
std::string id = StringFromFormat("%08x", m_LastID);
|
||||||
SElement Element;
|
SElement Element;
|
||||||
memcpy(Element.FileName, id.c_str(), 8);
|
memcpy(Element.FileName, id.c_str(), 8);
|
||||||
memcpy(Element.SHA1Hash, _pHash, 20);
|
memcpy(Element.SHA1Hash, hash, 20);
|
||||||
m_Elements.push_back(Element);
|
m_Elements.push_back(Element);
|
||||||
|
|
||||||
File::CreateFullPath(m_contentMap);
|
File::CreateFullPath(m_ContentMap);
|
||||||
|
|
||||||
File::IOFile pFile(m_contentMap, "ab");
|
File::IOFile pFile(m_ContentMap, "ab");
|
||||||
pFile.WriteArray(&Element, 1);
|
pFile.WriteArray(&Element, 1);
|
||||||
|
|
||||||
filename = StringFromFormat("%s/shared1/%s.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), id.c_str());
|
filename = StringFromFormat("%s/shared1/%s.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), id.c_str());
|
||||||
m_lastID++;
|
m_LastID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CNANDContentDataFile::EnsureOpen()
|
||||||
|
{
|
||||||
|
if (!m_file)
|
||||||
|
m_file = std::make_unique<File::IOFile>(m_filename, "rb");
|
||||||
|
else if (!m_file->IsOpen())
|
||||||
|
m_file->Open(m_filename, "rb");
|
||||||
|
}
|
||||||
|
void CNANDContentDataFile::Open()
|
||||||
|
{
|
||||||
|
EnsureOpen();
|
||||||
|
}
|
||||||
|
const std::vector<u8> CNANDContentDataFile::Get()
|
||||||
|
{
|
||||||
|
std::vector<u8> result;
|
||||||
|
EnsureOpen();
|
||||||
|
if (!m_file->IsGood())
|
||||||
|
return result;
|
||||||
|
|
||||||
CNANDContentLoader::CNANDContentLoader(const std::string& name)
|
u64 size = m_file->GetSize();
|
||||||
|
if (size == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result.resize(size);
|
||||||
|
m_file->ReadBytes(result.data(), result.size());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNANDContentDataFile::GetRange(u32 start, u32 size, u8* buffer)
|
||||||
|
{
|
||||||
|
EnsureOpen();
|
||||||
|
if (!m_file->IsGood())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_file->Seek(start, SEEK_SET))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return m_file->ReadBytes(buffer, static_cast<size_t>(size));
|
||||||
|
}
|
||||||
|
void CNANDContentDataFile::Close()
|
||||||
|
{
|
||||||
|
if (m_file && m_file->IsOpen())
|
||||||
|
m_file->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CNANDContentDataBuffer::GetRange(u32 start, u32 size, u8* buffer)
|
||||||
|
{
|
||||||
|
if (start + size > m_buffer.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::copy(&m_buffer[start], &m_buffer[start + size], buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CNANDContentLoader::CNANDContentLoader(const std::string& content_name)
|
||||||
: m_Valid(false)
|
: m_Valid(false)
|
||||||
, m_isWAD(false)
|
, m_IsWAD(false)
|
||||||
, m_TitleID(-1)
|
, m_TitleID(-1)
|
||||||
, m_IosVersion(0x09)
|
, m_IosVersion(0x09)
|
||||||
, m_BootIndex(-1)
|
, m_BootIndex(-1)
|
||||||
{
|
{
|
||||||
m_Valid = Initialize(name);
|
m_Valid = Initialize(content_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNANDContentLoader::~CNANDContentLoader()
|
CNANDContentLoader::~CNANDContentLoader()
|
||||||
@ -132,9 +187,9 @@ bool CNANDContentLoader::Initialize(const std::string& name)
|
|||||||
|
|
||||||
if (wad.IsValid())
|
if (wad.IsValid())
|
||||||
{
|
{
|
||||||
m_isWAD = true;
|
m_IsWAD = true;
|
||||||
m_ticket = wad.GetTicket();
|
m_Ticket = wad.GetTicket();
|
||||||
decrypted_title_key = GetKeyFromTicket(m_ticket);
|
decrypted_title_key = GetKeyFromTicket(m_Ticket);
|
||||||
tmd = wad.GetTMD();
|
tmd = wad.GetTMD();
|
||||||
data_app = wad.GetDataApp();
|
data_app = wad.GetDataApp();
|
||||||
}
|
}
|
||||||
@ -162,7 +217,7 @@ bool CNANDContentLoader::Initialize(const std::string& name)
|
|||||||
std::copy(&tmd[0x180], &tmd[0x180 + TMD_VIEW_SIZE], m_TMDView);
|
std::copy(&tmd[0x180], &tmd[0x180 + TMD_VIEW_SIZE], m_TMDView);
|
||||||
|
|
||||||
m_TitleVersion = Common::swap16(&tmd[0x01DC]);
|
m_TitleVersion = Common::swap16(&tmd[0x01DC]);
|
||||||
m_numEntries = Common::swap16(&tmd[0x01DE]);
|
m_NumEntries = Common::swap16(&tmd[0x01DE]);
|
||||||
m_BootIndex = Common::swap16(&tmd[0x01E0]);
|
m_BootIndex = Common::swap16(&tmd[0x01E0]);
|
||||||
m_TitleID = Common::swap64(&tmd[0x018C]);
|
m_TitleID = Common::swap64(&tmd[0x018C]);
|
||||||
m_IosVersion = Common::swap16(&tmd[0x018A]);
|
m_IosVersion = Common::swap16(&tmd[0x018A]);
|
||||||
@ -177,12 +232,12 @@ bool CNANDContentLoader::Initialize(const std::string& name)
|
|||||||
|
|
||||||
void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, const std::vector<u8>& decrypted_title_key, const std::vector<u8>& data_app)
|
void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, const std::vector<u8>& decrypted_title_key, const std::vector<u8>& data_app)
|
||||||
{
|
{
|
||||||
m_Content.resize(m_numEntries);
|
m_Content.resize(m_NumEntries);
|
||||||
|
|
||||||
std::array<u8, 16> iv;
|
std::array<u8, 16> iv;
|
||||||
u32 data_app_offset = 0;
|
u32 data_app_offset = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < m_numEntries; i++)
|
for (u32 i = 0; i < m_NumEntries; i++)
|
||||||
{
|
{
|
||||||
const u32 entry_offset = 0x24 * i;
|
const u32 entry_offset = 0x24 * i;
|
||||||
|
|
||||||
@ -200,27 +255,30 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, co
|
|||||||
const auto hash_end = std::next(hash_begin, ArraySize(content.m_SHA1Hash));
|
const auto hash_end = std::next(hash_begin, ArraySize(content.m_SHA1Hash));
|
||||||
std::copy(hash_begin, hash_end, content.m_SHA1Hash);
|
std::copy(hash_begin, hash_end, content.m_SHA1Hash);
|
||||||
|
|
||||||
if (m_isWAD)
|
if (m_IsWAD)
|
||||||
{
|
{
|
||||||
u32 rounded_size = ROUND_UP(content.m_Size, 0x40);
|
u32 rounded_size = ROUND_UP(content.m_Size, 0x40);
|
||||||
|
|
||||||
iv.fill(0);
|
iv.fill(0);
|
||||||
std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin());
|
std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin());
|
||||||
|
|
||||||
content.m_data = AESDecode(decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size);
|
content.m_Data = std::make_unique<CNANDContentDataBuffer>(AESDecode(decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size));
|
||||||
|
|
||||||
data_app_offset += rounded_size;
|
data_app_offset += rounded_size;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string filename;
|
||||||
if (content.m_Type & 0x8000) // shared app
|
if (content.m_Type & 0x8000) // shared app
|
||||||
content.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
|
filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
|
||||||
else
|
else
|
||||||
content.m_Filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID);
|
filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID);
|
||||||
|
|
||||||
|
content.m_Data = std::make_unique<CNANDContentDataFile>(filename);
|
||||||
|
|
||||||
// Be graceful about incorrect TMDs.
|
// Be graceful about incorrect TMDs.
|
||||||
if (File::Exists(content.m_Filename))
|
if (File::Exists(filename))
|
||||||
content.m_Size = static_cast<u32>(File::GetSize(content.m_Filename));
|
content.m_Size = static_cast<u32>(File::GetSize(filename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +350,7 @@ void CNANDContentLoader::RemoveTitle() const
|
|||||||
if (IsValid())
|
if (IsValid())
|
||||||
{
|
{
|
||||||
// remove TMD?
|
// remove TMD?
|
||||||
for (u32 i = 0; i < m_numEntries; i++)
|
for (u32 i = 0; i < m_NumEntries; i++)
|
||||||
{
|
{
|
||||||
if (!(m_Content[i].m_Type & 0x8000)) // skip shared apps
|
if (!(m_Content[i].m_Type & 0x8000)) // skip shared apps
|
||||||
{
|
{
|
||||||
@ -313,14 +371,14 @@ cUIDsys::cUIDsys()
|
|||||||
void cUIDsys::UpdateLocation()
|
void cUIDsys::UpdateLocation()
|
||||||
{
|
{
|
||||||
m_Elements.clear();
|
m_Elements.clear();
|
||||||
m_lastUID = 0x00001000;
|
m_LastUID = 0x00001000;
|
||||||
m_uidSys = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/sys/uid.sys";
|
m_UidSys = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/sys/uid.sys";
|
||||||
|
|
||||||
File::IOFile pFile(m_uidSys, "rb");
|
File::IOFile pFile(m_UidSys, "rb");
|
||||||
SElement Element;
|
SElement Element;
|
||||||
while (pFile.ReadArray(&Element, 1))
|
while (pFile.ReadArray(&Element, 1))
|
||||||
{
|
{
|
||||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
*(u32*)&(Element.UID) = Common::swap32(m_LastUID++);
|
||||||
m_Elements.push_back(Element);
|
m_Elements.push_back(Element);
|
||||||
}
|
}
|
||||||
pFile.Close();
|
pFile.Close();
|
||||||
@ -328,23 +386,23 @@ void cUIDsys::UpdateLocation()
|
|||||||
if (m_Elements.empty())
|
if (m_Elements.empty())
|
||||||
{
|
{
|
||||||
*(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU);
|
*(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU);
|
||||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
*(u32*)&(Element.UID) = Common::swap32(m_LastUID++);
|
||||||
|
|
||||||
File::CreateFullPath(m_uidSys);
|
File::CreateFullPath(m_UidSys);
|
||||||
pFile.Open(m_uidSys, "wb");
|
pFile.Open(m_UidSys, "wb");
|
||||||
if (!pFile.WriteArray(&Element, 1))
|
if (!pFile.WriteArray(&Element, 1))
|
||||||
ERROR_LOG(DISCIO, "Failed to write to %s", m_uidSys.c_str());
|
ERROR_LOG(DISCIO, "Failed to write to %s", m_UidSys.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cUIDsys::~cUIDsys()
|
cUIDsys::~cUIDsys()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
u32 cUIDsys::GetUIDFromTitle(u64 _Title)
|
u32 cUIDsys::GetUIDFromTitle(u64 title_id)
|
||||||
{
|
{
|
||||||
for (auto& Element : m_Elements)
|
for (auto& Element : m_Elements)
|
||||||
{
|
{
|
||||||
if (Common::swap64(_Title) == *(u64*)&(Element.titleID))
|
if (Common::swap64(title_id) == *(u64*)&(Element.titleID))
|
||||||
{
|
{
|
||||||
return Common::swap32(Element.UID);
|
return Common::swap32(Element.UID);
|
||||||
}
|
}
|
||||||
@ -352,33 +410,33 @@ u32 cUIDsys::GetUIDFromTitle(u64 _Title)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cUIDsys::AddTitle(u64 _TitleID)
|
void cUIDsys::AddTitle(u64 title_id)
|
||||||
{
|
{
|
||||||
if (GetUIDFromTitle(_TitleID))
|
if (GetUIDFromTitle(title_id))
|
||||||
{
|
{
|
||||||
INFO_LOG(DISCIO, "Title %08x%08x, already exists in uid.sys", (u32)(_TitleID >> 32), (u32)_TitleID);
|
INFO_LOG(DISCIO, "Title %08x%08x, already exists in uid.sys", (u32)(title_id >> 32), (u32)title_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SElement Element;
|
SElement Element;
|
||||||
*(u64*)&(Element.titleID) = Common::swap64(_TitleID);
|
*(u64*)&(Element.titleID) = Common::swap64(title_id);
|
||||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
*(u32*)&(Element.UID) = Common::swap32(m_LastUID++);
|
||||||
m_Elements.push_back(Element);
|
m_Elements.push_back(Element);
|
||||||
|
|
||||||
File::CreateFullPath(m_uidSys);
|
File::CreateFullPath(m_UidSys);
|
||||||
File::IOFile pFile(m_uidSys, "ab");
|
File::IOFile pFile(m_UidSys, "ab");
|
||||||
|
|
||||||
if (!pFile.WriteArray(&Element, 1))
|
if (!pFile.WriteArray(&Element, 1))
|
||||||
ERROR_LOG(DISCIO, "fwrite failed");
|
ERROR_LOG(DISCIO, "fwrite failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cUIDsys::GetTitleIDs(std::vector<u64>& _TitleIDs, bool _owned)
|
void cUIDsys::GetTitleIDs(std::vector<u64>& title_ids, bool owned)
|
||||||
{
|
{
|
||||||
for (auto& Element : m_Elements)
|
for (auto& Element : m_Elements)
|
||||||
{
|
{
|
||||||
if ((_owned && Common::CheckTitleTIK(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)) ||
|
if ((owned && Common::CheckTitleTIK(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)) ||
|
||||||
(!_owned && Common::CheckTitleTMD(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)))
|
(!owned && Common::CheckTitleTMD(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)))
|
||||||
_TitleIDs.push_back(Common::swap64(Element.titleID));
|
title_ids.push_back(Common::swap64(Element.titleID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +487,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
app_file.WriteBytes(content.m_data.data(), content.m_Size);
|
app_file.WriteBytes(content.m_Data->Get().data(), content.m_Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,41 @@ namespace DiscIO
|
|||||||
{
|
{
|
||||||
bool AddTicket(u64 title_id, const std::vector<u8>& ticket);
|
bool AddTicket(u64 title_id, const std::vector<u8>& ticket);
|
||||||
|
|
||||||
|
class CNANDContentData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Open() { };
|
||||||
|
virtual const std::vector<u8> Get() = 0;
|
||||||
|
virtual bool GetRange(u32 start, u32 size, u8* buffer) = 0;
|
||||||
|
virtual void Close() { };
|
||||||
|
};
|
||||||
|
|
||||||
|
class CNANDContentDataFile final : public CNANDContentData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CNANDContentDataFile(const std::string& filename) : m_filename(filename) { };
|
||||||
|
|
||||||
|
void Open() override;
|
||||||
|
const std::vector<u8> Get() override;
|
||||||
|
bool GetRange(u32 start, u32 size, u8* buffer) override;
|
||||||
|
void Close() override;
|
||||||
|
private:
|
||||||
|
void EnsureOpen();
|
||||||
|
|
||||||
|
const std::string m_filename;
|
||||||
|
std::unique_ptr<File::IOFile> m_file;
|
||||||
|
};
|
||||||
|
class CNANDContentDataBuffer final : public CNANDContentData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CNANDContentDataBuffer(const std::vector<u8>& buffer) : m_buffer(buffer) { };
|
||||||
|
|
||||||
|
const std::vector<u8> Get() override { return m_buffer; };
|
||||||
|
bool GetRange(u32 start, u32 size, u8* buffer) override;
|
||||||
|
private:
|
||||||
|
const std::vector<u8> m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
struct SNANDContent
|
struct SNANDContent
|
||||||
{
|
{
|
||||||
u32 m_ContentID;
|
u32 m_ContentID;
|
||||||
@ -26,34 +61,33 @@ struct SNANDContent
|
|||||||
u8 m_SHA1Hash[20];
|
u8 m_SHA1Hash[20];
|
||||||
u8 m_Header[36]; //all of the above
|
u8 m_Header[36]; //all of the above
|
||||||
|
|
||||||
std::string m_Filename;
|
std::unique_ptr<CNANDContentData> m_Data;
|
||||||
std::vector<u8> m_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Instances of this class must be created by CNANDContentManager
|
// Instances of this class must be created by CNANDContentManager
|
||||||
class CNANDContentLoader final
|
class CNANDContentLoader final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CNANDContentLoader(const std::string& _rName);
|
CNANDContentLoader(const std::string& content_name);
|
||||||
virtual ~CNANDContentLoader();
|
virtual ~CNANDContentLoader();
|
||||||
|
|
||||||
bool IsValid() const { return m_Valid; }
|
bool IsValid() const { return m_Valid; }
|
||||||
void RemoveTitle() const;
|
void RemoveTitle() const;
|
||||||
u64 GetTitleID() const { return m_TitleID; }
|
u64 GetTitleID() const { return m_TitleID; }
|
||||||
u16 GetIosVersion() const { return m_IosVersion; }
|
u16 GetIosVersion() const { return m_IosVersion; }
|
||||||
u32 GetBootIndex() const { return m_BootIndex; }
|
u32 GetBootIndex() const { return m_BootIndex; }
|
||||||
size_t GetContentSize() const { return m_Content.size(); }
|
size_t GetContentSize() const { return m_Content.size(); }
|
||||||
const SNANDContent* GetContentByIndex(int index) const;
|
const SNANDContent* GetContentByIndex(int index) const;
|
||||||
const u8* GetTMDView() const { return m_TMDView; }
|
const u8* GetTMDView() const { return m_TMDView; }
|
||||||
const u8* GetTMDHeader() const { return m_TMDHeader; }
|
const u8* GetTMDHeader() const { return m_TMDHeader; }
|
||||||
const std::vector<u8>& GetTicket() const { return m_ticket; }
|
const std::vector<u8>& GetTicket() const { return m_Ticket; }
|
||||||
|
|
||||||
const std::vector<SNANDContent>& GetContent() const { return m_Content; }
|
const std::vector<SNANDContent>& GetContent() const { return m_Content; }
|
||||||
|
|
||||||
u16 GetTitleVersion() const {return m_TitleVersion;}
|
u16 GetTitleVersion() const { return m_TitleVersion; }
|
||||||
u16 GetNumEntries() const {return m_numEntries;}
|
u16 GetNumEntries() const { return m_NumEntries; }
|
||||||
DiscIO::IVolume::ECountry GetCountry() const;
|
DiscIO::IVolume::ECountry GetCountry() const;
|
||||||
u8 GetCountryChar() const {return m_Country; }
|
u8 GetCountryChar() const { return m_Country; }
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -71,16 +105,16 @@ private:
|
|||||||
static std::vector<u8> GetKeyFromTicket(const std::vector<u8>& ticket);
|
static std::vector<u8> GetKeyFromTicket(const std::vector<u8>& ticket);
|
||||||
|
|
||||||
bool m_Valid;
|
bool m_Valid;
|
||||||
bool m_isWAD;
|
bool m_IsWAD;
|
||||||
std::string m_Path;
|
std::string m_Path;
|
||||||
u64 m_TitleID;
|
u64 m_TitleID;
|
||||||
u16 m_IosVersion;
|
u16 m_IosVersion;
|
||||||
u32 m_BootIndex;
|
u32 m_BootIndex;
|
||||||
u16 m_numEntries;
|
u16 m_NumEntries;
|
||||||
u16 m_TitleVersion;
|
u16 m_TitleVersion;
|
||||||
u8 m_TMDView[TMD_VIEW_SIZE];
|
u8 m_TMDView[TMD_VIEW_SIZE];
|
||||||
u8 m_TMDHeader[TMD_HEADER_SIZE];
|
u8 m_TMDHeader[TMD_HEADER_SIZE];
|
||||||
std::vector<u8> m_ticket;
|
std::vector<u8> m_Ticket;
|
||||||
u8 m_Country;
|
u8 m_Country;
|
||||||
|
|
||||||
std::vector<SNANDContent> m_Content;
|
std::vector<SNANDContent> m_Content;
|
||||||
@ -96,7 +130,7 @@ public:
|
|||||||
|
|
||||||
const CNANDContentLoader& GetNANDLoader(const std::string& content_path);
|
const CNANDContentLoader& GetNANDLoader(const std::string& content_path);
|
||||||
const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from);
|
const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from);
|
||||||
bool RemoveTitle(u64 titl_id, Common::FromWhichRoot from);
|
bool RemoveTitle(u64 title_id, Common::FromWhichRoot from);
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -114,8 +148,8 @@ class CSharedContent
|
|||||||
public:
|
public:
|
||||||
static CSharedContent& AccessInstance() { static CSharedContent instance; return instance; }
|
static CSharedContent& AccessInstance() { static CSharedContent instance; return instance; }
|
||||||
|
|
||||||
std::string GetFilenameFromSHA1(const u8* _pHash);
|
std::string GetFilenameFromSHA1(const u8* hash);
|
||||||
std::string AddSharedContent(const u8* _pHash);
|
std::string AddSharedContent(const u8* hash);
|
||||||
void UpdateLocation();
|
void UpdateLocation();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -133,8 +167,8 @@ private:
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
u32 m_lastID;
|
u32 m_LastID;
|
||||||
std::string m_contentMap;
|
std::string m_ContentMap;
|
||||||
std::vector<SElement> m_Elements;
|
std::vector<SElement> m_Elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,9 +177,9 @@ class cUIDsys
|
|||||||
public:
|
public:
|
||||||
static cUIDsys& AccessInstance() { static cUIDsys instance; return instance; }
|
static cUIDsys& AccessInstance() { static cUIDsys instance; return instance; }
|
||||||
|
|
||||||
u32 GetUIDFromTitle(u64 _Title);
|
u32 GetUIDFromTitle(u64 title_id);
|
||||||
void AddTitle(u64 _Title);
|
void AddTitle(u64 title_id);
|
||||||
void GetTitleIDs(std::vector<u64>& _TitleIDs, bool _owned = false);
|
void GetTitleIDs(std::vector<u64>& title_ids, bool owned = false);
|
||||||
void UpdateLocation();
|
void UpdateLocation();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -163,8 +197,8 @@ private:
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
u32 m_lastUID;
|
u32 m_LastUID;
|
||||||
std::string m_uidSys;
|
std::string m_UidSys;
|
||||||
std::vector<SElement> m_Elements;
|
std::vector<SElement> m_Elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user