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:
parent
8fd2f05741
commit
8a6d9e1e0b
|
@ -101,15 +101,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
|
|||
|
||||
WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename);
|
||||
|
||||
std::unique_ptr<CDolLoader> pDolLoader;
|
||||
if (pContent->m_data.empty())
|
||||
{
|
||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
|
||||
}
|
||||
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
|
||||
if (!pDolLoader->IsValid())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
for (auto& pair : m_ContentAccessMap)
|
||||
{
|
||||
delete pair.second.m_pFile;
|
||||
}
|
||||
m_ContentAccessMap.clear();
|
||||
m_TitleIDs.clear();
|
||||
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_Size = pContent->m_Size;
|
||||
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;
|
||||
return CFD;
|
||||
|
@ -401,25 +385,14 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
{
|
||||
if (pDest)
|
||||
{
|
||||
// FIXME: this breaks WAD access (the else part), fixed in the next commit
|
||||
//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;
|
||||
if (!pFile->Seek(rContent.m_Position, SEEK_SET))
|
||||
{
|
||||
ERROR_LOG(WII_IPC_ES, "ES: couldn't seek!");
|
||||
const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -452,7 +425,6 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
delete itr->second.m_pFile;
|
||||
m_ContentAccessMap.erase(itr);
|
||||
|
||||
Memory::Write_U32(0, _CommandAddress + 0x4);
|
||||
|
@ -915,15 +887,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
if (pContent)
|
||||
{
|
||||
tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT);
|
||||
std::unique_ptr<CDolLoader> pDolLoader;
|
||||
if (pContent->m_data.empty())
|
||||
{
|
||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_Filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDolLoader = std::make_unique<CDolLoader>(pContent->m_data);
|
||||
}
|
||||
std::unique_ptr<CDolLoader> pDolLoader = std::make_unique<CDolLoader>(pContent->m_Data->Get());
|
||||
|
||||
if (pDolLoader->IsValid())
|
||||
{
|
||||
|
|
|
@ -127,8 +127,6 @@ private:
|
|||
u64 m_TitleID;
|
||||
u16 m_Index;
|
||||
u32 m_Size;
|
||||
// This is a (raw) pointer to work around a MSVC bug.
|
||||
File::IOFile* m_pFile;
|
||||
};
|
||||
|
||||
typedef std::map<u32, SContentAccess> CContentAccessMap;
|
||||
|
|
|
@ -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)
|
||||
: m_Valid(false)
|
||||
, m_IsWAD(false)
|
||||
|
@ -207,20 +247,23 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd, co
|
|||
iv.fill(0);
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
if (content.m_Type & 0x8000) // shared app
|
||||
content.m_Filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
|
||||
filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash);
|
||||
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.
|
||||
if (File::Exists(content.m_Filename))
|
||||
content.m_Size = static_cast<u32>(File::GetSize(content.m_Filename));
|
||||
if (File::Exists(filename))
|
||||
content.m_Size = static_cast<u32>(File::GetSize(filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +472,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
app_file.WriteBytes(content.m_data.data(), content.m_Size);
|
||||
app_file.WriteBytes(content.m_Data->Get().data(), content.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -17,6 +17,34 @@ namespace DiscIO
|
|||
{
|
||||
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
|
||||
{
|
||||
u32 m_ContentID;
|
||||
|
@ -26,8 +54,7 @@ struct SNANDContent
|
|||
u8 m_SHA1Hash[20];
|
||||
u8 m_Header[36]; //all of the above
|
||||
|
||||
std::string m_Filename;
|
||||
std::vector<u8> m_data;
|
||||
std::unique_ptr<CNANDContentData> m_Data;
|
||||
};
|
||||
|
||||
// Instances of this class must be created by CNANDContentManager
|
||||
|
|
Loading…
Reference in New Issue