diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 7e0f13d338..425f93c6ed 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -324,10 +324,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) return AddTitleFinish(request); case IOCTL_ES_GETDEVICEID: return ESGetDeviceID(request); - case IOCTL_ES_GETTITLECONTENTSCNT: - return GetTitleContentsCount(request); - case IOCTL_ES_GETTITLECONTENTS: - return GetTitleContents(request); case IOCTL_ES_OPENTITLECONTENT: return OpenTitleContent(request); case IOCTL_ES_OPENCONTENT: @@ -354,6 +350,15 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) case IOCTL_ES_GETTITLES: return GetTitles(request); + case IOCTL_ES_GETTITLECONTENTSCNT: + return GetStoredContentsCount(request); + case IOCTL_ES_GETTITLECONTENTS: + return GetStoredContents(request); + case IOCTL_ES_GETSTOREDCONTENTCNT: + return GetTMDStoredContentsCount(request); + case IOCTL_ES_GETSTOREDCONTENTS: + return GetTMDStoredContents(request); + case IOCTL_ES_GETVIEWCNT: return GetViewCount(request); case IOCTL_ES_GETVIEWS: @@ -632,49 +637,109 @@ IPCCommandResult ES::ESGetDeviceID(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } -IPCCommandResult ES::GetTitleContentsCount(const IOCtlVRequest& request) +static std::vector GetStoredContentsFromTMD(const IOS::ES::TMDReader& tmd) { - if (!request.HasNumberOfValidVectors(1, 1)) + if (!tmd.IsValid()) + return {}; + + const DiscIO::CSharedContent shared{Common::FROM_SESSION_ROOT}; + const std::vector contents = tmd.GetContents(); + + std::vector stored_contents; + + std::copy_if(contents.begin(), contents.end(), std::back_inserter(stored_contents), + [&tmd, &shared](const auto& content) { + if (content.IsShared()) + { + const std::string path = shared.GetFilenameFromSHA1(content.sha1.data()); + return path != "unk" && File::Exists(path); + } + return File::Exists( + Common::GetTitleContentPath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT)); + }); + + return stored_contents; +} + +// Used by the GetStoredContents ioctlvs. This assumes that the first output vector +// is used for the content count (u32). +IPCCommandResult ES::GetStoredContentsCount(const IOS::ES::TMDReader& tmd, + const IOCtlVRequest& request) +{ + if (request.io_vectors[0].size != sizeof(u32) || !tmd.IsValid()) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); + const u16 num_contents = static_cast(GetStoredContentsFromTMD(tmd).size()); + Memory::Write_U32(num_contents, request.io_vectors[0].address); - const DiscIO::CNANDContentLoader& nand_content = AccessContentDevice(TitleID); - if (!nand_content.IsValid() || !nand_content.GetTMD().IsValid()) + INFO_LOG(IOS_ES, "GetStoredContentsCount (0x%x): %u content(s) for %016" PRIx64, request.request, + num_contents, tmd.GetTitleId()); + return GetDefaultReply(IPC_SUCCESS); +} + +// Used by the GetStoredContents ioctlvs. This assumes that the second input vector is used +// for the content count and the output vector is used to store a list of content IDs (u32s). +IPCCommandResult ES::GetStoredContents(const IOS::ES::TMDReader& tmd, const IOCtlVRequest& request) +{ + if (!tmd.IsValid()) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - const u16 num_contents = nand_content.GetTMD().GetNumContents(); + if (request.in_vectors[1].size != sizeof(u32) || + request.io_vectors[0].size != Memory::Read_U32(request.in_vectors[1].address) * sizeof(u32)) + { + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + } - if ((u32)(TitleID >> 32) == 0x00010000) - Memory::Write_U32(0, request.io_vectors[0].address); - else - Memory::Write_U32(num_contents, request.io_vectors[0].address); - - INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i", - (u32)(TitleID >> 32), (u32)TitleID, num_contents); + const auto contents = GetStoredContentsFromTMD(tmd); + const u32 max_content_count = Memory::Read_U32(request.in_vectors[1].address); + for (u32 i = 0; i < std::min(static_cast(contents.size()), max_content_count); ++i) + Memory::Write_U32(contents[i].id, request.io_vectors[0].address + i * sizeof(u32)); return GetDefaultReply(IPC_SUCCESS); } -IPCCommandResult ES::GetTitleContents(const IOCtlVRequest& request) +IPCCommandResult ES::GetStoredContentsCount(const IOCtlVRequest& request) +{ + if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u64)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); + const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id); + if (!content_loader.IsValid()) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + return GetStoredContentsCount(content_loader.GetTMD(), request); +} + +IPCCommandResult ES::GetStoredContents(const IOCtlVRequest& request) +{ + if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); + const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id); + if (!content_loader.IsValid()) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + return GetStoredContents(content_loader.GetTMD(), request); +} + +IPCCommandResult ES::GetTMDStoredContentsCount(const IOCtlVRequest& request) +{ + if (!request.HasNumberOfValidVectors(1, 1)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + std::vector tmd_bytes(request.in_vectors[0].size); + Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); + return GetStoredContentsCount(IOS::ES::TMDReader{std::move(tmd_bytes)}, request); +} + +IPCCommandResult ES::GetTMDStoredContents(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 1)) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); - - const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID); - if (!rNANDContent.IsValid() || !rNANDContent.GetTMD().IsValid()) - return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - - for (const auto& content : rNANDContent.GetTMD().GetContents()) - { - const u16 index = content.index; - Memory::Write_U32(content.id, request.io_vectors[0].address + index * 4); - INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", index, content.id); - } - - return GetDefaultReply(IPC_SUCCESS); + std::vector tmd_bytes(request.in_vectors[0].size); + Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); + return GetStoredContents(IOS::ES::TMDReader{std::move(tmd_bytes)}, request); } IPCCommandResult ES::OpenTitleContent(const IOCtlVRequest& request) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 24b7d172ee..f7da4381d8 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -157,8 +157,6 @@ private: IPCCommandResult AddContentFinish(const IOCtlVRequest& request); IPCCommandResult AddTitleFinish(const IOCtlVRequest& request); IPCCommandResult ESGetDeviceID(const IOCtlVRequest& request); - IPCCommandResult GetTitleContentsCount(const IOCtlVRequest& request); - IPCCommandResult GetTitleContents(const IOCtlVRequest& request); IPCCommandResult OpenTitleContent(const IOCtlVRequest& request); IPCCommandResult OpenContent(const IOCtlVRequest& request); IPCCommandResult ReadContent(const IOCtlVRequest& request); @@ -175,6 +173,14 @@ private: IPCCommandResult GetTitleCount(const IOCtlVRequest& request); IPCCommandResult GetTitles(const IOCtlVRequest& request); + IPCCommandResult GetStoredContentsCount(const IOS::ES::TMDReader& tmd, + const IOCtlVRequest& request); + IPCCommandResult GetStoredContents(const IOS::ES::TMDReader& tmd, const IOCtlVRequest& request); + IPCCommandResult GetStoredContentsCount(const IOCtlVRequest& request); + IPCCommandResult GetStoredContents(const IOCtlVRequest& request); + IPCCommandResult GetTMDStoredContentsCount(const IOCtlVRequest& request); + IPCCommandResult GetTMDStoredContents(const IOCtlVRequest& request); + IPCCommandResult GetViewCount(const IOCtlVRequest& request); IPCCommandResult GetViews(const IOCtlVRequest& request); IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);