diff options
author | t895 <clombardo169@gmail.com> | 2024-01-19 06:56:43 +0100 |
---|---|---|
committer | t895 <clombardo169@gmail.com> | 2024-01-19 23:09:35 +0100 |
commit | ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69 (patch) | |
tree | 552347f0f71c9341a139f929907fef9243c6e337 /src/frontend_common/content_manager.h | |
parent | Merge pull request #12713 from shinra-electric/mvk-127 (diff) | |
download | yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar.gz yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar.bz2 yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar.lz yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar.xz yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.tar.zst yuzu-ccd3dd842f2bf7cf16c7b93e3b83a2afc8af4a69.zip |
Diffstat (limited to '')
-rw-r--r-- | src/frontend_common/content_manager.h | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h new file mode 100644 index 000000000..8e55f4ca0 --- /dev/null +++ b/src/frontend_common/content_manager.h @@ -0,0 +1,168 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <boost/algorithm/string.hpp> +#include "common/common_types.h" +#include "common/literals.h" +#include "core/core.h" +#include "core/file_sys/common_funcs.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/mode.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/submission_package.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace ContentManager { + +enum class InstallResult { + Success, + Overwrite, + Failure, + BaseInstallAttempted, +}; + +inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_controller, + const u64 title_id) { + return fs_controller.GetUserNANDContents()->RemoveExistingEntry(title_id) || + fs_controller.GetSDMCContents()->RemoveExistingEntry(title_id); +} + +inline size_t RemoveAllDLC(Core::System* system, const u64 program_id) { + size_t count{}; + const auto& fs_controller = system->GetFileSystemController(); + const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( + FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); + std::vector<u64> program_dlc_entries; + + for (const auto& entry : dlc_entries) { + if (FileSys::GetBaseTitleID(entry.title_id) == program_id) { + program_dlc_entries.push_back(entry.title_id); + } + } + + for (const auto& entry : program_dlc_entries) { + if (RemoveDLC(fs_controller, entry)) { + ++count; + } + } + return count; +} + +inline bool RemoveUpdate(const Service::FileSystem::FileSystemController& fs_controller, + const u64 program_id) { + const auto update_id = program_id | 0x800; + return fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || + fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id); +} + +inline bool RemoveBaseContent(const Service::FileSystem::FileSystemController& fs_controller, + const u64 program_id) { + return fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || + fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); +} + +inline InstallResult InstallNSP( + Core::System* system, FileSys::VfsFilesystem* vfs, const std::string& filename, + const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { + const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, + std::size_t block_size) { + if (src == nullptr || dest == nullptr) { + return false; + } + if (!dest->Resize(src->GetSize())) { + return false; + } + + using namespace Common::Literals; + std::vector<u8> buffer(1_MiB); + + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { + if (callback(src->GetSize(), i)) { + dest->Resize(0); + return false; + } + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); + } + return true; + }; + + std::shared_ptr<FileSys::NSP> nsp; + FileSys::VirtualFile file = vfs->OpenFile(filename, FileSys::Mode::Read); + if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { + nsp = std::make_shared<FileSys::NSP>(file); + if (nsp->IsExtractedType()) { + return InstallResult::Failure; + } + } else { + return InstallResult::Failure; + } + + if (nsp->GetStatus() != Loader::ResultStatus::Success) { + return InstallResult::Failure; + } + const auto res = + system->GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy); + switch (res) { + case FileSys::InstallResult::Success: + return InstallResult::Success; + case FileSys::InstallResult::OverwriteExisting: + return InstallResult::Overwrite; + case FileSys::InstallResult::ErrorBaseInstall: + return InstallResult::BaseInstallAttempted; + default: + return InstallResult::Failure; + } +} + +inline InstallResult InstallNCA( + FileSys::VfsFilesystem* vfs, const std::string& filename, + FileSys::RegisteredCache* registered_cache, const FileSys::TitleType title_type, + const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { + const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, + std::size_t block_size) { + if (src == nullptr || dest == nullptr) { + return false; + } + if (!dest->Resize(src->GetSize())) { + return false; + } + + using namespace Common::Literals; + std::vector<u8> buffer(1_MiB); + + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { + if (callback(src->GetSize(), i)) { + dest->Resize(0); + return false; + } + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); + } + return true; + }; + + const auto nca = std::make_shared<FileSys::NCA>(vfs->OpenFile(filename, FileSys::Mode::Read)); + const auto id = nca->GetStatus(); + + // Game updates necessary are missing base RomFS + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + return InstallResult::Failure; + } + + const auto res = registered_cache->InstallEntry(*nca, title_type, true, copy); + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::OverwriteExisting) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; + } +} + +} // namespace ContentManager |