From 8a6d9e1e0b2fe407dd986b4982ca77e91f0604c3 Mon Sep 17 00:00:00 2001 From: BhaaL Date: Wed, 16 Mar 2016 20:08:37 +0100 Subject: [PATCH] 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. --- Source/Core/Core/Boot/Boot_WiiWAD.cpp | 10 +--- .../Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 50 +++-------------- .../Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h | 2 - Source/Core/DiscIO/NANDContentLoader.cpp | 55 +++++++++++++++++-- Source/Core/DiscIO/NANDContentLoader.h | 31 ++++++++++- 5 files changed, 86 insertions(+), 62 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 00bca2eb97..2d27231426 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -101,15 +101,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename) WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename); - std::unique_ptr pDolLoader; - if (pContent->m_data.empty()) - { - pDolLoader = std::make_unique(pContent->m_Filename); - } - else - { - pDolLoader = std::make_unique(pContent->m_data); - } + std::unique_ptr pDolLoader = std::make_unique(pContent->m_Data->Get()); if (!pDolLoader->IsValid()) return false; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 3f28100833..87a8c41351 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -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!"); - } - 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!"); - } + 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); } - /*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 pDolLoader; - if (pContent->m_data.empty()) - { - pDolLoader = std::make_unique(pContent->m_Filename); - } - else - { - pDolLoader = std::make_unique(pContent->m_data); - } + std::unique_ptr pDolLoader = std::make_unique(pContent->m_Data->Get()); if (pDolLoader->IsValid()) { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h index 07b5fbede4..a0d0d72065 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -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 CContentAccessMap; diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 0ab9383802..6a9fc29bdf 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -92,6 +92,46 @@ std::string CSharedContent::AddSharedContent(const u8* hash) } +const std::vector CNANDContentDataFile::Get() +{ + std::vector 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)); +} + + +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& 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(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(filename); // Be graceful about incorrect TMDs. - if (File::Exists(content.m_Filename)) - content.m_Size = static_cast(File::GetSize(content.m_Filename)); + if (File::Exists(filename)) + content.m_Size = static_cast(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 { diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h index 911d6110e9..c82d46db1f 100644 --- a/Source/Core/DiscIO/NANDContentLoader.h +++ b/Source/Core/DiscIO/NANDContentLoader.h @@ -17,6 +17,34 @@ namespace DiscIO { bool AddTicket(u64 title_id, const std::vector& ticket); +class CNANDContentData +{ +public: + virtual const std::vector 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 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& buffer) : m_buffer(buffer) { }; + + const std::vector Get() override { return m_buffer; }; + bool GetRange(u32 start, u32 size, u8* buffer) override; +private: + const std::vector 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 m_data; + std::unique_ptr m_Data; }; // Instances of this class must be created by CNANDContentManager