From 8f08c2eb91d20498d93b69b43779bbb6831ff023 Mon Sep 17 00:00:00 2001 From: Adubbz Date: Fri, 13 Mar 2020 14:37:28 +1100 Subject: [PATCH] ncm: Implemented MemoryInstallTaskData --- .../ncm/ncm_install_task_data.hpp | 30 +++- .../source/ncm/ncm_install_task_data.cpp | 139 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_data.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_data.hpp index 12338b5f8..0dde8d3a3 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_data.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_data.hpp @@ -50,7 +50,35 @@ namespace ams::ncm { virtual Result Update(s32 index, const void *data, size_t data_size) = 0; }; - /* TODO: MemoryInstallTaskData */ + class MemoryInstallTaskData : public InstallTaskDataBase { + private: + struct DataHolder : public InstallContentMeta, public util::IntrusiveListBaseNode{}; + using DataList = util::IntrusiveListBaseTraits::ListType; + private: + DataList data_list; + InstallProgressState state; + Result last_result; + SystemUpdateTaskApplyInfo system_update_task_apply_info; + public: + MemoryInstallTaskData() { /* ... */ }; + ~MemoryInstallTaskData() { + this->Cleanup(); + } + public: + virtual Result GetProgress(InstallProgress *out_progress) override; + virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) override; + virtual Result SetState(InstallProgressState state) override; + virtual Result SetLastResult(Result result) override; + virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) override; + virtual Result Push(const void *data, size_t data_size) override; + virtual Result Count(s32 *out) override; + virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override; + virtual Result Cleanup() override; + private: + virtual Result GetSize(size_t *out_size, s32 index) override; + virtual Result Get(s32 index, void *out, size_t out_size) override; + virtual Result Update(s32 index, const void *data, size_t data_size) override; + }; class FileInstallTaskData : public InstallTaskDataBase { private: diff --git a/libraries/libstratosphere/source/ncm/ncm_install_task_data.cpp b/libraries/libstratosphere/source/ncm/ncm_install_task_data.cpp index 840c192a5..d55102ea0 100644 --- a/libraries/libstratosphere/source/ncm/ncm_install_task_data.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_install_task_data.cpp @@ -73,6 +73,145 @@ namespace ams::ncm { return ResultSuccess(); } + Result MemoryInstallTaskData::GetProgress(InstallProgress *out_progress) { + /* Initialize install progress. */ + InstallProgress install_progress = { + .state = this->state, + }; + install_progress.SetLastResult(this->last_result); + + /* Only states after prepared are allowed. */ + if (this->state != InstallProgressState::NotPrepared && this->state != InstallProgressState::DataPrepared) { + for (auto &data_holder : this->data_list) { + const InstallContentMetaReader reader = data_holder.GetReader(); + + /* Sum the sizes from this entry's content infos. */ + for (size_t i = 0; i < reader.GetContentCount(); i++) { + const InstallContentInfo *content_info = reader.GetContentInfo(i); + install_progress.installed_size += content_info->GetSize(); + install_progress.total_size += content_info->GetSizeWritten(); + } + } + } + + *out_progress = install_progress; + return ResultSuccess(); + } + + Result MemoryInstallTaskData::GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) { + *out_info = this->system_update_task_apply_info; + return ResultSuccess(); + } + + Result MemoryInstallTaskData::SetState(InstallProgressState state) { + this->state = state; + return ResultSuccess(); + } + + Result MemoryInstallTaskData::SetLastResult(Result result) { + this->last_result = result; + return ResultSuccess(); + } + + Result MemoryInstallTaskData::SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) { + this->system_update_task_apply_info = info; + return ResultSuccess(); + } + + Result MemoryInstallTaskData::Push(const void *data, size_t size) { + /* Allocate a new data holder. */ + auto holder = std::unique_ptr(new (std::nothrow) DataHolder()); + R_UNLESS(holder != nullptr, ncm::ResultAllocationFailed()); + + /* Allocate memory for the content meta data. */ + holder->data = std::unique_ptr(new (std::nothrow) char[size]); + R_UNLESS(holder->data != nullptr, ncm::ResultAllocationFailed()); + holder->size = size; + + /* Copy data to the data holder. */ + std::memcpy(holder->data.get(), data, size); + + /* Put the data holder into the data list. */ + this->data_list.push_back(*holder); + + /* Relinquish control over the memory allocated to the data holder. */ + holder.release(); + + return ResultSuccess(); + } + + Result MemoryInstallTaskData::Count(s32 *out) { + *out = this->data_list.size(); + return ResultSuccess(); + } + + Result MemoryInstallTaskData::GetSize(size_t *out_size, s32 index) { + /* Find the correct entry in the list. */ + s32 count = 0; + for (auto &data_holder : this->data_list) { + if (index == count++) { + *out_size = data_holder.size; + return ResultSuccess(); + } + } + /* Out of bounds indexing is an unrecoverable error. */ + AMS_ABORT(); + } + + Result MemoryInstallTaskData::Get(s32 index, void *out, size_t out_size) { + /* Find the correct entry in the list. */ + s32 count = 0; + for (auto &data_holder : this->data_list) { + if (index == count++) { + R_UNLESS(out_size >= data_holder.size, ncm::ResultBufferInsufficient()); + memcpy(out, data_holder.data.get(), data_holder.size); + return ResultSuccess(); + } + } + /* Out of bounds indexing is an unrecoverable error. */ + AMS_ABORT(); + } + + Result MemoryInstallTaskData::Update(s32 index, const void *data, size_t data_size) { + /* Find the correct entry in the list. */ + s32 count = 0; + for (auto &data_holder : this->data_list) { + if (index == count++) { + R_UNLESS(data_size == data_holder.size, ncm::ResultBufferInsufficient()); + memcpy(data_holder.data.get(), data, data_size); + return ResultSuccess(); + } + } + /* Out of bounds indexing is an unrecoverable error. */ + AMS_ABORT(); + } + Result MemoryInstallTaskData::Delete(const ContentMetaKey *keys, s32 num_keys) { + /* Iterate over keys. */ + for (s32 i = 0; i < num_keys; i++) { + const auto &key = keys[i]; + + /* Find and remove matching data from the list. */ + for (auto &data_holder : this->data_list) { + if (key == data_holder.GetReader().GetKey()) { + this->data_list.erase(this->data_list.iterator_to(data_holder)); + delete std::addressof(data_holder); + break; + } + } + } + + return ResultSuccess(); + } + + Result MemoryInstallTaskData::Cleanup() { + while (!this->data_list.empty()) { + auto *data_holder = std::addressof(this->data_list.front()); + this->data_list.pop_front(); + delete data_holder; + } + return ResultSuccess(); + } + Result FileInstallTaskData::Create(const char *path, s32 max_entries) { /* Create the file. */ R_TRY(fs::CreateFile(path, 0));