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);
|
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;
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue