From 68595831011b2a7f27e20f606b0f334e21cc4d9c Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Mar 2026 22:02:33 +0000 Subject: [PATCH] [hle/ns] implement IReadOnlyApplicationControlDataInterface::ListApplicationIcon Signed-off-by: lizzie --- .../ns/application_manager_interface.cpp | 7 +- .../ns/application_manager_interface.h | 1 + ...nly_application_control_data_interface.cpp | 153 +++++++++--------- ..._only_application_control_data_interface.h | 1 + ...read_only_application_record_interface.cpp | 8 +- 5 files changed, 92 insertions(+), 78 deletions(-) diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp index 5490c09d03..98559e1f8c 100644 --- a/src/core/hle/service/ns/application_manager_interface.cpp +++ b/src/core/hle/service/ns/application_manager_interface.cpp @@ -137,7 +137,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ {405, nullptr, "ListApplicationControlCacheEntryInfo"}, {406, nullptr, "GetApplicationControlProperty"}, {407, &IApplicationManagerInterface::ListApplicationTitle, "ListApplicationTitle"}, - {408, nullptr, "ListApplicationIcon"}, + {408, &IApplicationManagerInterface::ListApplicationIcon, "ListApplicationIcon"}, {411, nullptr, "Unknown411"}, //19.0.0+ {412, nullptr, "Unknown412"}, //19.0.0+ {413, nullptr, "Unknown413"}, //19.0.0+ @@ -848,4 +848,9 @@ void IApplicationManagerInterface::ListApplicationTitle(HLERequestContext& ctx) IReadOnlyApplicationControlDataInterface(system).ListApplicationTitle(ctx); } +void IApplicationManagerInterface::ListApplicationIcon(HLERequestContext& ctx) { + LOG_DEBUG(Service_NS, "called"); + IReadOnlyApplicationControlDataInterface(system).ListApplicationIcon(ctx); +} + } // namespace Service::NS diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h index 245d59a068..052bee33c9 100644 --- a/src/core/hle/service/ns/application_manager_interface.h +++ b/src/core/hle/service/ns/application_manager_interface.h @@ -75,6 +75,7 @@ public: u64 application_id); void ListApplicationTitle(HLERequestContext& ctx); + void ListApplicationIcon(HLERequestContext& ctx); private: KernelHelpers::ServiceContext service_context; 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 index 03f0a17865..7f605441db 100644 --- 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 @@ -12,12 +12,16 @@ #include #include +#include "common/logging.h" #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/kernel/k_transfer_memory.h" +#include "core/hle/result.h" #include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/hle_ipc.h" #include "core/hle/service/ns/language.h" #include "core/hle/service/ns/ns_types.h" #include "core/hle/service/ns/ns_results.h" @@ -73,24 +77,26 @@ void SanitizeJPEGImageSize(std::vector& image) { // IAsyncValue implementation for ListApplicationTitle // https://switchbrew.org/wiki/NS_services#ListApplicationTitle -class IAsyncValueForListApplicationTitle final : public ServiceFramework { +class IAsyncValue final : public ServiceFramework { public: - explicit IAsyncValueForListApplicationTitle(Core::System& system_, s32 offset, s32 size) - : ServiceFramework{system_, "IAsyncValue"}, service_context{system_, "IAsyncValue"}, - data_offset{offset}, data_size{size} { + explicit IAsyncValue(Core::System& system_, s32 offset, s32 size) + : ServiceFramework{system_, "IAsyncValue"} + , service_context{system_, "IAsyncValue"} + , data_offset{offset} + , data_size{size} + { static const FunctionInfo functions[] = { - {0, &IAsyncValueForListApplicationTitle::GetSize, "GetSize"}, - {1, &IAsyncValueForListApplicationTitle::Get, "Get"}, - {2, &IAsyncValueForListApplicationTitle::Cancel, "Cancel"}, - {3, &IAsyncValueForListApplicationTitle::GetErrorContext, "GetErrorContext"}, + {0, D<&IAsyncValue::GetSize>, "GetSize"}, + {1, D<&IAsyncValue::Get>, "Get"}, + {2, D<&IAsyncValue::Cancel>, "Cancel"}, + {3, D<&IAsyncValue::GetErrorContext>, "GetErrorContext"}, }; RegisterHandlers(functions); - completion_event = service_context.CreateEvent("IAsyncValue:Completion"); completion_event->GetReadableEvent().Signal(); } - ~IAsyncValueForListApplicationTitle() override { + ~IAsyncValue() override { service_context.CloseEvent(completion_event); } @@ -99,35 +105,24 @@ public: } private: - void GetSize(HLERequestContext& ctx) { + Result GetSize(Out out_data_size) { LOG_DEBUG(Service_NS, "called"); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(data_size); + *out_data_size = data_size; + R_SUCCEED(); } - - void Get(HLERequestContext& ctx) { + Result Get(OutBuffer out_data_offset) { LOG_DEBUG(Service_NS, "called"); - std::vector buffer(sizeof(s32)); - std::memcpy(buffer.data(), &data_offset, sizeof(s32)); - ctx.WriteBuffer(buffer); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + std::memcpy(out_data_offset.data(), &data_offset, sizeof(s32)); + R_SUCCEED(); } - - void Cancel(HLERequestContext& ctx) { + Result Cancel() { LOG_DEBUG(Service_NS, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - - void GetErrorContext(HLERequestContext& ctx) { + Result GetErrorContext() { LOG_DEBUG(Service_NS, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - KernelHelpers::ServiceContext service_context; Kernel::KEvent* completion_event{}; s32 data_offset; @@ -145,6 +140,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, {4, nullptr, "SelectApplicationDesiredLanguage"}, {5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData2>, "GetApplicationControlData"}, + {10, &IReadOnlyApplicationControlDataInterface::ListApplicationIcon, "ListApplicationIcon"}, {13, &IReadOnlyApplicationControlDataInterface::ListApplicationTitle, "ListApplicationTitle"}, {19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"}, }; @@ -161,8 +157,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( 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 FileSys::PatchManager pm{application_id, system.GetFileSystemController(), system.GetContentProvider()}; const auto control = pm.GetControlMetadata(); const auto size = out_buffer.size(); @@ -170,8 +165,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( const auto total_size = sizeof(FileSys::RawNACP) + icon_size; if (size < total_size) { - LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", - size); + LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size); R_THROW(ResultUnknown); } @@ -179,8 +173,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( 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); + LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero", application_id); std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP)); } @@ -205,15 +198,12 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage( // 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); + 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); + LOG_ERROR(Service_NS, "Could not find application language priorities! application_language={}", *application_language); R_THROW(Service::NS::ResultApplicationLanguageNotFound); } @@ -257,8 +247,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData2( const auto nacp_size = sizeof(FileSys::RawNACP); if (size < nacp_size) { - LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min={:08X})", - size, nacp_size); + LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min={:08X})", size, nacp_size); R_THROW(ResultUnknown); } @@ -309,63 +298,83 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData2( R_SUCCEED(); } - -void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) { - /* - IPC::RequestParser rp{ctx}; - auto control_source = rp.PopRaw(); - rp.Skip(7, false); - auto transfer_memory_size = rp.Pop(); - */ +void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestContext& ctx) { + LOG_WARNING(Service_NS, "(stubbed)"); const auto app_ids_buffer = ctx.ReadBuffer(); - const size_t app_count = app_ids_buffer.size() / sizeof(u64); + const u64 app_count = app_ids_buffer.size() / sizeof(u64); + auto t_mem_obj = ctx.GetObjectFromHandle(ctx.GetCopyHandle(0)); + auto* t_mem = t_mem_obj.GetPointerUnsafe(); - std::vector application_ids(app_count); - if (app_count > 0) { - std::memcpy(application_ids.data(), app_ids_buffer.data(), app_count * sizeof(u64)); + size_t out_length = 0; + if (t_mem != nullptr && app_count > 0) { + auto& memory = system.ApplicationMemory(); + const auto t_mem_address = t_mem->GetSourceAddress(); + // u64 - app count + memory.WriteBlock(t_mem_address + out_length, &app_count, sizeof(u64)); + out_length += sizeof(u64); + // [list of u64] - size of icons + for (size_t i = 0; i < app_count; ++i) { + const u64 app_id = app_ids_buffer[i]; + const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + u64 full_size = control.second->GetSize(); + memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64)); + out_length += sizeof(u64); + } + // [list of raw icon data] + std::vector full_icon_data; + for (size_t i = 0; i < app_count; ++i) { + const u64 app_id = app_ids_buffer[i]; + const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + auto const full_size = control.second->GetSize(); + if (full_size > 0) { + full_icon_data.resize(full_size); + control.second->Read(full_icon_data.data(), full_size, 0); + memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size); + out_length += full_size; + } + } } + auto async_value = std::make_shared(system, 0, s32(out_length)); + IPC::ResponseBuilder rb{ctx, 2, 1, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(async_value->ReadableEvent()); + rb.PushIpcInterface(std::move(async_value)); +} +void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) { + const auto app_ids_buffer = ctx.ReadBuffer(); + const size_t app_count = app_ids_buffer.size() / sizeof(u64); auto t_mem_obj = ctx.GetObjectFromHandle(ctx.GetCopyHandle(0)); auto* t_mem = t_mem_obj.GetPointerUnsafe(); - constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry); const size_t total_data_size = app_count * title_entry_size; - constexpr s32 data_offset = 0; - if (t_mem != nullptr && app_count > 0) { auto& memory = system.ApplicationMemory(); const auto t_mem_address = t_mem->GetSourceAddress(); - for (size_t i = 0; i < app_count; ++i) { - const u64 app_id = application_ids[i]; - const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), - system.GetContentProvider()}; + const u64 app_id = app_ids_buffer[i]; + const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()}; const auto control = pm.GetControlMetadata(); - FileSys::LanguageEntry entry{}; if (control.first != nullptr) { entry = control.first->GetLanguageEntry(); } - const size_t offset = i * title_entry_size; memory.WriteBlock(t_mem_address + offset, &entry, title_entry_size); } } - - auto async_value = std::make_shared( - system, data_offset, static_cast(total_data_size)); - + auto async_value = std::make_shared(system, data_offset, s32(total_data_size)); IPC::ResponseBuilder rb{ctx, 2, 1, 1}; rb.Push(ResultSuccess); rb.PushCopyObjects(async_value->ReadableEvent()); rb.PushIpcInterface(std::move(async_value)); } -Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3( - OutBuffer out_buffer, Out out_flags_a, Out out_flags_b, - Out out_actual_size, ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) { +Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(OutBuffer out_buffer, Out out_flags_a, Out out_flags_b, Out out_actual_size, ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) { LOG_INFO(Service_NS, "called with control_source={}, flags=({:02X},{:02X}), application_id={:016X}", application_control_source, flag1, flag2, application_id); 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 index 441408b651..a4a285151a 100644 --- 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 @@ -34,6 +34,7 @@ public: u8 flag1, u8 flag2, u64 application_id); + void ListApplicationIcon(HLERequestContext& ctx); void ListApplicationTitle(HLERequestContext& ctx); Result GetApplicationControlData3( OutBuffer out_buffer, diff --git a/src/core/hle/service/ns/read_only_application_record_interface.cpp b/src/core/hle/service/ns/read_only_application_record_interface.cpp index 18f9e41d8c..8ce7851ae2 100644 --- a/src/core/hle/service/ns/read_only_application_record_interface.cpp +++ b/src/core/hle/service/ns/read_only_application_record_interface.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project @@ -16,10 +16,8 @@ IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::S static const FunctionInfo functions[] = { {0, D<&IReadOnlyApplicationRecordInterface::HasApplicationRecord>, "HasApplicationRecord"}, {1, nullptr, "NotifyApplicationFailure"}, - {2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>, - "IsDataCorruptedResult"}, - {3, D<&IReadOnlyApplicationRecordInterface::ListApplicationRecord>, - "ListApplicationRecord"}, + {2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>, "IsDataCorruptedResult"}, + {3, D<&IReadOnlyApplicationRecordInterface::ListApplicationRecord>, "ListApplicationRecord"}, }; // clang-format on