From 2eded86b4b525fad4221115b716700d63ad8438f Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 17 Feb 2024 13:46:18 -0500 Subject: [PATCH] ns: rewrite IReadOnlyApplicationControlDataInterface --- src/core/CMakeLists.txt | 2 + src/core/hle/service/ns/ns.cpp | 46 +------ src/core/hle/service/ns/ns.h | 10 -- src/core/hle/service/ns/ns_types.h | 6 + ...nly_application_control_data_interface.cpp | 122 ++++++++++++++++++ ..._only_application_control_data_interface.h | 29 +++++ 6 files changed, 160 insertions(+), 55 deletions(-) create mode 100644 src/core/hle/service/ns/read_only_application_control_data_interface.cpp create mode 100644 src/core/hle/service/ns/read_only_application_control_data_interface.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ab8b1c6c98..bc515949c9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -765,6 +765,8 @@ add_library(core STATIC hle/service/ns/pdm_qry.h hle/service/ns/platform_service_manager.cpp hle/service/ns/platform_service_manager.h + hle/service/ns/read_only_application_control_data_interface.cpp + hle/service/ns/read_only_application_control_data_interface.h hle/service/ns/read_only_application_record_interface.cpp hle/service/ns/read_only_application_record_interface.h hle/service/nvdrv/core/container.cpp diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 5dc15dad58..b5ad27dd89 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -24,6 +24,7 @@ #include "core/hle/service/ns/ns_results.h" #include "core/hle/service/ns/pdm_qry.h" #include "core/hle/service/ns/platform_service_manager.h" +#include "core/hle/service/ns/read_only_application_control_data_interface.h" #include "core/hle/service/ns/read_only_application_record_interface.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/set/settings_server.h" @@ -469,51 +470,6 @@ Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( return ResultSuccess; } -IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( - Core::System& system_) - : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IReadOnlyApplicationControlDataInterface::GetApplicationControlData, "GetApplicationControlData"}, - {1, nullptr, "GetApplicationDesiredLanguage"}, - {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, - {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, - {4, nullptr, "SelectApplicationDesiredLanguage"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; - -void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequestContext& ctx) { - enum class ApplicationControlSource : u8 { - CacheOnly, - Storage, - StorageOnly, - }; - - struct RequestParameters { - ApplicationControlSource source; - u64 application_id; - }; - static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size."); - - IPC::RequestParser rp{ctx}; - std::vector nacp_data{}; - const auto parameters{rp.PopRaw()}; - const auto result = - system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id); - - if (result == ResultSuccess) { - ctx.WriteBuffer(nacp_data.data(), nacp_data.size()); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { // clang-format off static const FunctionInfo functions[] = { diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 20a2243ff9..39a6b6f21d 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -32,16 +32,6 @@ private: void ConvertApplicationLanguageToLanguageCode(HLERequestContext& ctx); }; -class IReadOnlyApplicationControlDataInterface final - : public ServiceFramework { -public: - explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); - ~IReadOnlyApplicationControlDataInterface() override; - -private: - void GetApplicationControlData(HLERequestContext& ctx); -}; - class NS final : public ServiceFramework { public: explicit NS(const char* name, Core::System& system_); diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h index d7c16eac0f..fa2aad3d99 100644 --- a/src/core/hle/service/ns/ns_types.h +++ b/src/core/hle/service/ns/ns_types.h @@ -16,6 +16,12 @@ enum class ApplicationRecordType : u8 { GameCard = 0x10, }; +enum class ApplicationControlSource : u8 { + CacheOnly = 0, + Storage = 1, + StorageOnly = 2, +}; + struct ApplicationRecord { u64 application_id; ApplicationRecordType type; diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.cpp b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp new file mode 100644 index 0000000000..6b47515961 --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ns/language.h" +#include "core/hle/service/ns/ns_results.h" +#include "core/hle/service/ns/read_only_application_control_data_interface.h" +#include "core/hle/service/set/settings_server.h" + +namespace Service::NS { + +IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( + Core::System& system_) + : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"}, + {1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"}, + {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"}, + {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, + {4, nullptr, "SelectApplicationDesiredLanguage"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; + +Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( + OutBuffer out_buffer, Out out_actual_size, + ApplicationControlSource application_control_source, u64 application_id) { + LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}", + application_control_source, application_id); + + const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), + system.GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto size = out_buffer.size(); + + const auto icon_size = control.second ? control.second->GetSize() : 0; + const auto total_size = 0x4000 + icon_size; + + if (size < total_size) { + LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", + size); + R_THROW(ResultUnknown); + } + + if (control.first != nullptr) { + const auto bytes = control.first->GetRawBytes(); + std::memcpy(out_buffer.data(), bytes.data(), bytes.size()); + } else { + LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero", + application_id); + std::memset(out_buffer.data(), 0, 0x4000); + } + + if (control.second != nullptr) { + control.second->Read(out_buffer.data() + 0x4000, icon_size); + } else { + LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id); + } + + *out_actual_size = static_cast(total_size); + R_SUCCEED(); +} + +Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage( + Out out_desired_language, u32 supported_languages) { + LOG_INFO(Service_NS, "called with supported_languages={:08X}", supported_languages); + + // Get language code from settings + const auto language_code = + Set::GetLanguageCodeFromIndex(static_cast(Settings::values.language_index.GetValue())); + + // Convert to application language, get priority list + const auto application_language = ConvertToApplicationLanguage(language_code); + if (application_language == std::nullopt) { + LOG_ERROR(Service_NS, "Could not convert application language! language_code={}", + language_code); + R_THROW(Service::NS::ResultApplicationLanguageNotFound); + } + const auto priority_list = GetApplicationLanguagePriorityList(*application_language); + if (!priority_list) { + LOG_ERROR(Service_NS, + "Could not find application language priorities! application_language={}", + *application_language); + R_THROW(Service::NS::ResultApplicationLanguageNotFound); + } + + // Try to find a valid language. + for (const auto lang : *priority_list) { + const auto supported_flag = GetSupportedLanguageFlag(lang); + if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) { + *out_desired_language = static_cast(lang); + R_SUCCEED(); + } + } + + LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}", + supported_languages); + R_THROW(Service::NS::ResultApplicationLanguageNotFound); +} + +Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode( + Out out_language_code, ApplicationLanguage application_language) { + const auto language_code = ConvertToLanguageCode(application_language); + if (language_code == std::nullopt) { + LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language); + R_THROW(Service::NS::ResultApplicationLanguageNotFound); + } + + *out_language_code = static_cast(*language_code); + R_SUCCEED(); +} + +} // namespace Service::NS diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.h b/src/core/hle/service/ns/read_only_application_control_data_interface.h new file mode 100644 index 0000000000..7d470c4322 --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/ns/language.h" +#include "core/hle/service/ns/ns_types.h" +#include "core/hle/service/service.h" + +namespace Service::NS { + +class IReadOnlyApplicationControlDataInterface final + : public ServiceFramework { +public: + explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); + ~IReadOnlyApplicationControlDataInterface() override; + +private: + Result GetApplicationControlData(OutBuffer out_buffer, + Out out_actual_size, + ApplicationControlSource application_control_source, + u64 application_id); + Result GetApplicationDesiredLanguage(Out out_desired_language, u32 supported_languages); + Result ConvertApplicationLanguageToLanguageCode(Out out_language_code, + ApplicationLanguage application_language); +}; + +} // namespace Service::NS