hide the distinction between WAD and File from ES

instead, leave all the management with the NANDContentLoader.

for file data (directly on the NAND), this opens the file on-demand and
returns the requested chunk when asked for it.
for on-the-fly decrypted WAD data, we just keep the decoded buffer in
memory, like we've done before - except that we don't give away any objects
we don't want to.
This commit is contained in:
BhaaL 2016-03-16 20:08:37 +01:00
parent 8fd2f05741
commit 8a6d9e1e0b
5 changed files with 86 additions and 62 deletions

View File

@ -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;

View File

@ -185,10 +185,6 @@ 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)
{ {
for (auto& pair : m_ContentAccessMap)
{
delete pair.second.m_pFile;
}
m_ContentAccessMap.clear(); m_ContentAccessMap.clear();
m_TitleIDs.clear(); m_TitleIDs.clear();
m_TitleID = -1; m_TitleID = -1;
@ -223,20 +219,8 @@ u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index)
Access.m_Index = pContent->m_Index; Access.m_Index = pContent->m_Index;
Access.m_Size = pContent->m_Size; Access.m_Size = pContent->m_Size;
Access.m_TitleID = TitleID; Access.m_TitleID = TitleID;
Access.m_pFile = nullptr;
if (pContent->m_data.empty())
{
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;
@ -401,25 +385,14 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
{ {
if (pDest) if (pDest)
{ {
// FIXME: this breaks WAD access (the else part), fixed in the next commit const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID);
//if (rContent.m_pContent->m_data.empty()) // 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;
} }
@ -452,7 +425,6 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
return GetDefaultReply(); return GetDefaultReply();
} }
delete itr->second.m_pFile;
m_ContentAccessMap.erase(itr); m_ContentAccessMap.erase(itr);
Memory::Write_U32(0, _CommandAddress + 0x4); Memory::Write_U32(0, _CommandAddress + 0x4);
@ -915,15 +887,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())
{ {

View File

@ -127,8 +127,6 @@ private:
u64 m_TitleID; u64 m_TitleID;
u16 m_Index; u16 m_Index;
u32 m_Size; u32 m_Size;
// This is a (raw) pointer to work around a MSVC bug.
File::IOFile* m_pFile;
}; };
typedef std::map<u32, SContentAccess> CContentAccessMap; typedef std::map<u32, SContentAccess> CContentAccessMap;

View File

@ -92,6 +92,46 @@ std::string CSharedContent::AddSharedContent(const u8* hash)
} }
const std::vector<u8> CNANDContentDataFile::Get()
{
std::vector<u8> result;
File::IOFile file(m_filename, "rb");
if (!file.IsGood())
return result;
u64 size = file.GetSize();
if (size == 0)
return result;
result.resize(size);
file.ReadBytes(result.data(), result.size());
return result;
}
bool CNANDContentDataFile::GetRange(u32 start, u32 size, u8* buffer)
{
File::IOFile file(m_filename, "rb");
if (!file.IsGood())
return false;
if (!file.Seek(start, SEEK_SET))
return false;
return file.ReadBytes(buffer, static_cast<size_t>(size));
}
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) CNANDContentLoader::CNANDContentLoader(const std::string& content_name)
: m_Valid(false) : m_Valid(false)
, m_IsWAD(false) , m_IsWAD(false)
@ -207,20 +247,23 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, co
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));
} }
} }
@ -429,7 +472,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
{ {

View File

@ -17,6 +17,34 @@ 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 const std::vector<u8> Get() = 0;
virtual bool GetRange(u32 start, u32 size, u8* buffer) = 0;
};
class CNANDContentDataFile final : public CNANDContentData
{
public:
CNANDContentDataFile(const std::string& filename) : m_filename(filename) { };
const std::vector<u8> Get() override;
bool GetRange(u32 start, u32 size, u8* buffer) override;
private:
const std::string m_filename;
};
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,8 +54,7 @@ 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