summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt8
-rw-r--r--src/core/hle/service/am/am.cpp106
-rw-r--r--src/core/hle/service/am/am.h20
-rw-r--r--src/core/hle/service/am/applet_ae.cpp20
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp5
-rw-r--r--src/core/hle/service/caps/caps.cpp21
-rw-r--r--src/core/hle/service/caps/caps.h81
-rw-r--r--src/core/hle/service/caps/caps_a.cpp239
-rw-r--r--src/core/hle/service/caps/caps_a.h21
-rw-r--r--src/core/hle/service/caps/caps_c.cpp50
-rw-r--r--src/core/hle/service/caps/caps_c.h10
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp342
-rw-r--r--src/core/hle/service/caps/caps_manager.h72
-rw-r--r--src/core/hle/service/caps/caps_result.h35
-rw-r--r--src/core/hle/service/caps/caps_sc.cpp5
-rw-r--r--src/core/hle/service/caps/caps_sc.h6
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp5
-rw-r--r--src/core/hle/service/caps/caps_ss.h6
-rw-r--r--src/core/hle/service/caps/caps_su.cpp9
-rw-r--r--src/core/hle/service/caps/caps_su.h6
-rw-r--r--src/core/hle/service/caps/caps_types.h184
-rw-r--r--src/core/hle/service/caps/caps_u.cpp104
-rw-r--r--src/core/hle/service/caps/caps_u.h12
-rw-r--r--src/core/hle/service/nifm/nifm.cpp12
-rw-r--r--src/core/hle/service/nifm/nifm.h1
-rw-r--r--src/core/hle/service/ns/ns.cpp27
-rw-r--r--src/core/hle/service/ns/ns.h4
-rw-r--r--src/core/hle/service/pctl/pctl_module.cpp9
-rw-r--r--src/yuzu/main.cpp25
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui6
31 files changed, 1206 insertions, 246 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e02ededfc..e4f499135 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -466,14 +466,18 @@ add_library(core STATIC
466 hle/service/caps/caps_a.h 466 hle/service/caps/caps_a.h
467 hle/service/caps/caps_c.cpp 467 hle/service/caps/caps_c.cpp
468 hle/service/caps/caps_c.h 468 hle/service/caps/caps_c.h
469 hle/service/caps/caps_u.cpp 469 hle/service/caps/caps_manager.cpp
470 hle/service/caps/caps_u.h 470 hle/service/caps/caps_manager.h
471 hle/service/caps/caps_result.h
471 hle/service/caps/caps_sc.cpp 472 hle/service/caps/caps_sc.cpp
472 hle/service/caps/caps_sc.h 473 hle/service/caps/caps_sc.h
473 hle/service/caps/caps_ss.cpp 474 hle/service/caps/caps_ss.cpp
474 hle/service/caps/caps_ss.h 475 hle/service/caps/caps_ss.h
475 hle/service/caps/caps_su.cpp 476 hle/service/caps/caps_su.cpp
476 hle/service/caps/caps_su.h 477 hle/service/caps/caps_su.h
478 hle/service/caps/caps_types.h
479 hle/service/caps/caps_u.cpp
480 hle/service/caps/caps_u.h
477 hle/service/erpt/erpt.cpp 481 hle/service/erpt/erpt.cpp
478 hle/service/erpt/erpt.h 482 hle/service/erpt/erpt.h
479 hle/service/es/es.cpp 483 hle/service/es/es.cpp
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 819dea6a7..ac376b55a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -31,7 +31,7 @@
31#include "core/hle/service/apm/apm_controller.h" 31#include "core/hle/service/apm/apm_controller.h"
32#include "core/hle/service/apm/apm_interface.h" 32#include "core/hle/service/apm/apm_interface.h"
33#include "core/hle/service/bcat/backend/backend.h" 33#include "core/hle/service/bcat/backend/backend.h"
34#include "core/hle/service/caps/caps.h" 34#include "core/hle/service/caps/caps_types.h"
35#include "core/hle/service/filesystem/filesystem.h" 35#include "core/hle/service/filesystem/filesystem.h"
36#include "core/hle/service/ipc_helpers.h" 36#include "core/hle/service/ipc_helpers.h"
37#include "core/hle/service/ns/ns.h" 37#include "core/hle/service/ns/ns.h"
@@ -764,6 +764,66 @@ void AppletMessageQueue::OperationModeChanged() {
764 on_operation_mode_changed->Signal(); 764 on_operation_mode_changed->Signal();
765} 765}
766 766
767ILockAccessor::ILockAccessor(Core::System& system_)
768 : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
769 // clang-format off
770 static const FunctionInfo functions[] = {
771 {1, &ILockAccessor::TryLock, "TryLock"},
772 {2, &ILockAccessor::Unlock, "Unlock"},
773 {3, &ILockAccessor::GetEvent, "GetEvent"},
774 {4,&ILockAccessor::IsLocked, "IsLocked"},
775 };
776 // clang-format on
777
778 RegisterHandlers(functions);
779
780 lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
781}
782
783ILockAccessor::~ILockAccessor() = default;
784
785void ILockAccessor::TryLock(HLERequestContext& ctx) {
786 IPC::RequestParser rp{ctx};
787 const auto return_handle = rp.Pop<bool>();
788
789 LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
790
791 // TODO: When return_handle is true this function should return the lock handle
792
793 is_locked = true;
794
795 IPC::ResponseBuilder rb{ctx, 3};
796 rb.Push(ResultSuccess);
797 rb.Push<u8>(is_locked);
798}
799
800void ILockAccessor::Unlock(HLERequestContext& ctx) {
801 LOG_INFO(Service_AM, "called");
802
803 is_locked = false;
804
805 IPC::ResponseBuilder rb{ctx, 2};
806 rb.Push(ResultSuccess);
807}
808
809void ILockAccessor::GetEvent(HLERequestContext& ctx) {
810 LOG_INFO(Service_AM, "called");
811
812 lock_event->Signal();
813
814 IPC::ResponseBuilder rb{ctx, 2, 1};
815 rb.Push(ResultSuccess);
816 rb.PushCopyObjects(lock_event->GetReadableEvent());
817}
818
819void ILockAccessor::IsLocked(HLERequestContext& ctx) {
820 LOG_INFO(Service_AM, "called");
821
822 IPC::ResponseBuilder rb{ctx, 2};
823 rb.Push(ResultSuccess);
824 rb.Push<u8>(is_locked);
825}
826
767ICommonStateGetter::ICommonStateGetter(Core::System& system_, 827ICommonStateGetter::ICommonStateGetter(Core::System& system_,
768 std::shared_ptr<AppletMessageQueue> msg_queue_) 828 std::shared_ptr<AppletMessageQueue> msg_queue_)
769 : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, 829 : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
@@ -787,7 +847,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
787 {14, nullptr, "GetWakeupCount"}, 847 {14, nullptr, "GetWakeupCount"},
788 {20, nullptr, "PushToGeneralChannel"}, 848 {20, nullptr, "PushToGeneralChannel"},
789 {30, nullptr, "GetHomeButtonReaderLockAccessor"}, 849 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
790 {31, nullptr, "GetReaderLockAccessorEx"}, 850 {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
791 {32, nullptr, "GetWriterLockAccessorEx"}, 851 {32, nullptr, "GetWriterLockAccessorEx"},
792 {40, nullptr, "GetCradleFwVersion"}, 852 {40, nullptr, "GetCradleFwVersion"},
793 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, 853 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
@@ -805,7 +865,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
805 {65, nullptr, "GetApplicationIdByContentActionName"}, 865 {65, nullptr, "GetApplicationIdByContentActionName"},
806 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, 866 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
807 {67, nullptr, "CancelCpuBoostMode"}, 867 {67, nullptr, "CancelCpuBoostMode"},
808 {68, nullptr, "GetBuiltInDisplayType"}, 868 {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
809 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, 869 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
810 {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, 870 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
811 {91, nullptr, "GetCurrentPerformanceConfiguration"}, 871 {91, nullptr, "GetCurrentPerformanceConfiguration"},
@@ -886,6 +946,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
886 rb.Push(ResultSuccess); 946 rb.Push(ResultSuccess);
887} 947}
888 948
949void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
950 IPC::RequestParser rp{ctx};
951 const auto unknown = rp.Pop<u32>();
952
953 LOG_INFO(Service_AM, "called, unknown={}", unknown);
954
955 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
956
957 rb.Push(ResultSuccess);
958 rb.PushIpcInterface<ILockAccessor>(system);
959}
960
889void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { 961void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
890 LOG_WARNING(Service_AM, "called"); 962 LOG_WARNING(Service_AM, "called");
891 963
@@ -970,6 +1042,14 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
970 apm_sys->SetCpuBoostMode(ctx); 1042 apm_sys->SetCpuBoostMode(ctx);
971} 1043}
972 1044
1045void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
1046 LOG_WARNING(Service_AM, "(STUBBED) called");
1047
1048 IPC::ResponseBuilder rb{ctx, 3};
1049 rb.Push(ResultSuccess);
1050 rb.Push(0);
1051}
1052
973void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { 1053void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
974 IPC::RequestParser rp{ctx}; 1054 IPC::RequestParser rp{ctx};
975 const auto system_button{rp.PopEnum<SystemButtonType>()}; 1055 const auto system_button{rp.PopEnum<SystemButtonType>()};
@@ -1493,6 +1573,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
1493 case Applets::AppletId::MiiEdit: 1573 case Applets::AppletId::MiiEdit:
1494 PushInShowMiiEditData(); 1574 PushInShowMiiEditData();
1495 break; 1575 break;
1576 case Applets::AppletId::PhotoViewer:
1577 PushInShowAlbum();
1578 break;
1496 default: 1579 default:
1497 break; 1580 break;
1498 } 1581 }
@@ -1569,6 +1652,23 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
1569 rb.PushRaw(applet_info); 1652 rb.PushRaw(applet_info);
1570} 1653}
1571 1654
1655void ILibraryAppletSelfAccessor::PushInShowAlbum() {
1656 const Applets::CommonArguments arguments{
1657 .arguments_version = Applets::CommonArgumentVersion::Version3,
1658 .size = Applets::CommonArgumentSize::Version3,
1659 .library_version = 1,
1660 .theme_color = Applets::ThemeColor::BasicBlack,
1661 .play_startup_sound = true,
1662 .system_tick = system.CoreTiming().GetClockTicks(),
1663 };
1664
1665 std::vector<u8> argument_data(sizeof(arguments));
1666 std::vector<u8> settings_data{2};
1667 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1668 queue_data.emplace_back(std::move(argument_data));
1669 queue_data.emplace_back(std::move(settings_data));
1670}
1671
1572void ILibraryAppletSelfAccessor::PushInShowCabinetData() { 1672void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
1573 const Applets::CommonArguments arguments{ 1673 const Applets::CommonArguments arguments{
1574 .arguments_version = Applets::CommonArgumentVersion::Version3, 1674 .arguments_version = Applets::CommonArgumentVersion::Version3,
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 349482dcc..4a045cfd4 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -195,6 +195,23 @@ private:
195 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; 195 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
196}; 196};
197 197
198class ILockAccessor final : public ServiceFramework<ILockAccessor> {
199public:
200 explicit ILockAccessor(Core::System& system_);
201 ~ILockAccessor() override;
202
203private:
204 void TryLock(HLERequestContext& ctx);
205 void Unlock(HLERequestContext& ctx);
206 void GetEvent(HLERequestContext& ctx);
207 void IsLocked(HLERequestContext& ctx);
208
209 bool is_locked{};
210
211 Kernel::KEvent* lock_event;
212 KernelHelpers::ServiceContext service_context;
213};
214
198class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 215class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
199public: 216public:
200 explicit ICommonStateGetter(Core::System& system_, 217 explicit ICommonStateGetter(Core::System& system_,
@@ -237,6 +254,7 @@ private:
237 void GetCurrentFocusState(HLERequestContext& ctx); 254 void GetCurrentFocusState(HLERequestContext& ctx);
238 void RequestToAcquireSleepLock(HLERequestContext& ctx); 255 void RequestToAcquireSleepLock(HLERequestContext& ctx);
239 void GetAcquiredSleepLockEvent(HLERequestContext& ctx); 256 void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
257 void GetReaderLockAccessorEx(HLERequestContext& ctx);
240 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); 258 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
241 void GetOperationMode(HLERequestContext& ctx); 259 void GetOperationMode(HLERequestContext& ctx);
242 void GetPerformanceMode(HLERequestContext& ctx); 260 void GetPerformanceMode(HLERequestContext& ctx);
@@ -248,6 +266,7 @@ private:
248 void EndVrModeEx(HLERequestContext& ctx); 266 void EndVrModeEx(HLERequestContext& ctx);
249 void GetDefaultDisplayResolution(HLERequestContext& ctx); 267 void GetDefaultDisplayResolution(HLERequestContext& ctx);
250 void SetCpuBoostMode(HLERequestContext& ctx); 268 void SetCpuBoostMode(HLERequestContext& ctx);
269 void GetBuiltInDisplayType(HLERequestContext& ctx);
251 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); 270 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
252 void GetSettingsPlatformRegion(HLERequestContext& ctx); 271 void GetSettingsPlatformRegion(HLERequestContext& ctx);
253 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); 272 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
@@ -327,6 +346,7 @@ private:
327 void ExitProcessAndReturn(HLERequestContext& ctx); 346 void ExitProcessAndReturn(HLERequestContext& ctx);
328 void GetCallerAppletIdentityInfo(HLERequestContext& ctx); 347 void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
329 348
349 void PushInShowAlbum();
330 void PushInShowCabinetData(); 350 void PushInShowCabinetData();
331 void PushInShowMiiEditData(); 351 void PushInShowMiiEditData();
332 352
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index eb12312cc..e30e6478a 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -28,8 +28,8 @@ public:
28 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, 28 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
29 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, 29 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
30 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, 30 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
31 {22, nullptr, "GetHomeMenuFunctions"}, 31 {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
32 {23, nullptr, "GetGlobalStateController"}, 32 {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
33 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, 33 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
34 }; 34 };
35 // clang-format on 35 // clang-format on
@@ -110,6 +110,22 @@ private:
110 rb.PushIpcInterface<IAppletCommonFunctions>(system); 110 rb.PushIpcInterface<IAppletCommonFunctions>(system);
111 } 111 }
112 112
113 void GetHomeMenuFunctions(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_AM, "called");
115
116 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
117 rb.Push(ResultSuccess);
118 rb.PushIpcInterface<IHomeMenuFunctions>(system);
119 }
120
121 void GetGlobalStateController(HLERequestContext& ctx) {
122 LOG_DEBUG(Service_AM, "called");
123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(ResultSuccess);
126 rb.PushIpcInterface<IGlobalStateController>(system);
127 }
128
113 void GetDebugFunctions(HLERequestContext& ctx) { 129 void GetDebugFunctions(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_AM, "called"); 130 LOG_DEBUG(Service_AM, "called");
115 131
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index b46ea840c..5d17c353f 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -138,6 +138,10 @@ void Error::Initialize() {
138 CopyArgumentData(data, args->application_error); 138 CopyArgumentData(data, args->application_error);
139 error_code = Result(args->application_error.error_code); 139 error_code = Result(args->application_error.error_code);
140 break; 140 break;
141 case ErrorAppletMode::ShowErrorPctl:
142 CopyArgumentData(data, args->error_record);
143 error_code = Decode64BitError(args->error_record.error_code_64);
144 break;
141 case ErrorAppletMode::ShowErrorRecord: 145 case ErrorAppletMode::ShowErrorRecord:
142 CopyArgumentData(data, args->error_record); 146 CopyArgumentData(data, args->error_record);
143 error_code = Decode64BitError(args->error_record.error_code_64); 147 error_code = Decode64BitError(args->error_record.error_code_64);
@@ -191,6 +195,7 @@ void Error::Execute() {
191 frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback); 195 frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
192 break; 196 break;
193 } 197 }
198 case ErrorAppletMode::ShowErrorPctl:
194 case ErrorAppletMode::ShowErrorRecord: 199 case ErrorAppletMode::ShowErrorRecord:
195 reporter.SaveErrorReport(title_id, error_code, 200 reporter.SaveErrorReport(title_id, error_code,
196 fmt::format("{:016X}", args->error_record.posix_time)); 201 fmt::format("{:016X}", args->error_record.posix_time));
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index 610fe9940..286f9fd10 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -4,6 +4,7 @@
4#include "core/hle/service/caps/caps.h" 4#include "core/hle/service/caps/caps.h"
5#include "core/hle/service/caps/caps_a.h" 5#include "core/hle/service/caps/caps_a.h"
6#include "core/hle/service/caps/caps_c.h" 6#include "core/hle/service/caps/caps_c.h"
7#include "core/hle/service/caps/caps_manager.h"
7#include "core/hle/service/caps/caps_sc.h" 8#include "core/hle/service/caps/caps_sc.h"
8#include "core/hle/service/caps/caps_ss.h" 9#include "core/hle/service/caps/caps_ss.h"
9#include "core/hle/service/caps/caps_su.h" 10#include "core/hle/service/caps/caps_su.h"
@@ -15,13 +16,21 @@ namespace Service::Capture {
15 16
16void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
17 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
19 auto album_manager = std::make_shared<AlbumManager>();
20
21 server_manager->RegisterNamedService(
22 "caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager));
23 server_manager->RegisterNamedService(
24 "caps:c", std::make_shared<IAlbumControlService>(system, album_manager));
25 server_manager->RegisterNamedService(
26 "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
27
28 server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
29 server_manager->RegisterNamedService("caps:sc",
30 std::make_shared<IScreenShotControlService>(system));
31 server_manager->RegisterNamedService("caps:su",
32 std::make_shared<IScreenShotApplicationService>(system));
18 33
19 server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(system));
20 server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system));
21 server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system));
22 server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system));
23 server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system));
24 server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system));
25 ServerManager::RunServer(std::move(server_manager)); 34 ServerManager::RunServer(std::move(server_manager));
26} 35}
27 36
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
index 15f0ecfaa..58e9725b8 100644
--- a/src/core/hle/service/caps/caps.h
+++ b/src/core/hle/service/caps/caps.h
@@ -3,93 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Core { 6namespace Core {
10class System; 7class System;
11} 8}
12 9
13namespace Service::SM {
14class ServiceManager;
15}
16
17namespace Service::Capture { 10namespace Service::Capture {
18 11
19enum class AlbumImageOrientation {
20 Orientation0 = 0,
21 Orientation1 = 1,
22 Orientation2 = 2,
23 Orientation3 = 3,
24};
25
26enum class AlbumReportOption : s32 {
27 Disable = 0,
28 Enable = 1,
29};
30
31enum class ContentType : u8 {
32 Screenshot = 0,
33 Movie = 1,
34 ExtraMovie = 3,
35};
36
37enum class AlbumStorage : u8 {
38 NAND = 0,
39 SD = 1,
40};
41
42struct AlbumFileDateTime {
43 s16 year{};
44 s8 month{};
45 s8 day{};
46 s8 hour{};
47 s8 minute{};
48 s8 second{};
49 s8 uid{};
50};
51static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
52
53struct AlbumEntry {
54 u64 size{};
55 u64 application_id{};
56 AlbumFileDateTime datetime{};
57 AlbumStorage storage{};
58 ContentType content{};
59 INSERT_PADDING_BYTES(6);
60};
61static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
62
63struct AlbumFileEntry {
64 u64 size{}; // Size of the entry
65 u64 hash{}; // AES256 with hardcoded key over AlbumEntry
66 AlbumFileDateTime datetime{};
67 AlbumStorage storage{};
68 ContentType content{};
69 INSERT_PADDING_BYTES(5);
70 u8 unknown{1}; // Set to 1 on official SW
71};
72static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
73
74struct ApplicationAlbumEntry {
75 u64 size{}; // Size of the entry
76 u64 hash{}; // AES256 with hardcoded key over AlbumEntry
77 AlbumFileDateTime datetime{};
78 AlbumStorage storage{};
79 ContentType content{};
80 INSERT_PADDING_BYTES(5);
81 u8 unknown{1}; // Set to 1 on official SW
82};
83static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
84
85struct ApplicationAlbumFileEntry {
86 ApplicationAlbumEntry entry{};
87 AlbumFileDateTime datetime{};
88 u64 unknown{};
89};
90static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
91 "ApplicationAlbumFileEntry has incorrect size.");
92
93void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
94 13
95} // namespace Service::Capture 14} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index 44267b284..e22f72bf6 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -1,40 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
4#include "core/hle/service/caps/caps_a.h" 5#include "core/hle/service/caps/caps_a.h"
6#include "core/hle/service/caps/caps_manager.h"
7#include "core/hle/service/caps/caps_result.h"
8#include "core/hle/service/caps/caps_types.h"
9#include "core/hle/service/ipc_helpers.h"
5 10
6namespace Service::Capture { 11namespace Service::Capture {
7 12
8class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { 13IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
9public: 14 std::shared_ptr<AlbumManager> album_manager)
10 explicit IAlbumAccessorSession(Core::System& system_) 15 : ServiceFramework{system_, "caps:a"}, manager{album_manager} {
11 : ServiceFramework{system_, "IAlbumAccessorSession"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {2001, nullptr, "OpenAlbumMovieReadStream"},
15 {2002, nullptr, "CloseAlbumMovieReadStream"},
16 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
17 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
18 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
19 {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
20 {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
21 {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26 }
27};
28
29CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
30 // clang-format off 16 // clang-format off
31 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
32 {0, nullptr, "GetAlbumFileCount"}, 18 {0, nullptr, "GetAlbumFileCount"},
33 {1, nullptr, "GetAlbumFileList"}, 19 {1, nullptr, "GetAlbumFileList"},
34 {2, nullptr, "LoadAlbumFile"}, 20 {2, nullptr, "LoadAlbumFile"},
35 {3, nullptr, "DeleteAlbumFile"}, 21 {3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
36 {4, nullptr, "StorageCopyAlbumFile"}, 22 {4, nullptr, "StorageCopyAlbumFile"},
37 {5, nullptr, "IsAlbumMounted"}, 23 {5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
38 {6, nullptr, "GetAlbumUsage"}, 24 {6, nullptr, "GetAlbumUsage"},
39 {7, nullptr, "GetAlbumFileSize"}, 25 {7, nullptr, "GetAlbumFileSize"},
40 {8, nullptr, "LoadAlbumFileThumbnail"}, 26 {8, nullptr, "LoadAlbumFileThumbnail"},
@@ -47,18 +33,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
47 {15, nullptr, "GetAlbumUsage3"}, 33 {15, nullptr, "GetAlbumUsage3"},
48 {16, nullptr, "GetAlbumMountResult"}, 34 {16, nullptr, "GetAlbumMountResult"},
49 {17, nullptr, "GetAlbumUsage16"}, 35 {17, nullptr, "GetAlbumUsage16"},
50 {18, nullptr, "Unknown18"}, 36 {18, &IAlbumAccessorService::Unknown18, "Unknown18"},
51 {19, nullptr, "Unknown19"}, 37 {19, nullptr, "Unknown19"},
52 {100, nullptr, "GetAlbumFileCountEx0"}, 38 {100, nullptr, "GetAlbumFileCountEx0"},
53 {101, nullptr, "GetAlbumFileListEx0"}, 39 {101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
54 {202, nullptr, "SaveEditedScreenShot"}, 40 {202, nullptr, "SaveEditedScreenShot"},
55 {301, nullptr, "GetLastThumbnail"}, 41 {301, nullptr, "GetLastThumbnail"},
56 {302, nullptr, "GetLastOverlayMovieThumbnail"}, 42 {302, nullptr, "GetLastOverlayMovieThumbnail"},
57 {401, nullptr, "GetAutoSavingStorage"}, 43 {401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
58 {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, 44 {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
59 {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, 45 {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
60 {1002, nullptr, "LoadAlbumScreenShotImageEx1"}, 46 {1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
61 {1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"}, 47 {1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
62 {8001, nullptr, "ForceAlbumUnmounted"}, 48 {8001, nullptr, "ForceAlbumUnmounted"},
63 {8002, nullptr, "ResetAlbumMountStatus"}, 49 {8002, nullptr, "ResetAlbumMountStatus"},
64 {8011, nullptr, "RefreshAlbumCache"}, 50 {8011, nullptr, "RefreshAlbumCache"},
@@ -74,6 +60,199 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
74 RegisterHandlers(functions); 60 RegisterHandlers(functions);
75} 61}
76 62
77CAPS_A::~CAPS_A() = default; 63IAlbumAccessorService::~IAlbumAccessorService() = default;
64
65void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
66 IPC::RequestParser rp{ctx};
67 const auto file_id{rp.PopRaw<AlbumFileId>()};
68
69 LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
70 file_id.application_id, file_id.storage, file_id.type);
71
72 Result result = manager->DeleteAlbumFile(file_id);
73 result = TranslateResult(result);
74
75 IPC::ResponseBuilder rb{ctx, 2};
76 rb.Push(result);
77}
78
79void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx};
81 const auto storage{rp.PopEnum<AlbumStorage>()};
82
83 LOG_INFO(Service_Capture, "called, storage={}", storage);
84
85 Result result = manager->IsAlbumMounted(storage);
86 const bool is_mounted = result.IsSuccess();
87 result = TranslateResult(result);
88
89 IPC::ResponseBuilder rb{ctx, 3};
90 rb.Push(result);
91 rb.Push<u8>(is_mounted);
92}
93
94void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
95 struct UnknownBuffer {
96 INSERT_PADDING_BYTES(0x10);
97 };
98 static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
99
100 LOG_WARNING(Service_Capture, "(STUBBED) called");
101
102 std::vector<UnknownBuffer> buffer{};
103
104 if (!buffer.empty()) {
105 ctx.WriteBuffer(buffer);
106 }
107
108 IPC::ResponseBuilder rb{ctx, 3};
109 rb.Push(ResultSuccess);
110 rb.Push(static_cast<u32>(buffer.size()));
111}
112
113void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
114 IPC::RequestParser rp{ctx};
115 const auto storage{rp.PopEnum<AlbumStorage>()};
116 const auto flags{rp.Pop<u8>()};
117 const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()};
118
119 LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
120
121 std::vector<AlbumEntry> entries;
122 Result result = manager->GetAlbumFileList(entries, storage, flags);
123 result = TranslateResult(result);
124
125 entries.resize(std::min(album_entry_size, entries.size()));
126
127 if (!entries.empty()) {
128 ctx.WriteBuffer(entries);
129 }
130
131 IPC::ResponseBuilder rb{ctx, 3};
132 rb.Push(result);
133 rb.Push(entries.size());
134}
135
136void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
137 LOG_WARNING(Service_Capture, "(STUBBED) called");
138
139 bool is_autosaving{};
140 Result result = manager->GetAutoSavingStorage(is_autosaving);
141 result = TranslateResult(result);
142
143 IPC::ResponseBuilder rb{ctx, 3};
144 rb.Push(result);
145 rb.Push<u8>(is_autosaving);
146}
147
148void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
149 IPC::RequestParser rp{ctx};
150 const auto file_id{rp.PopRaw<AlbumFileId>()};
151 const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
152 const auto image_buffer_size{ctx.GetWriteBufferSize(1)};
153
154 LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
155 file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
156
157 std::vector<u8> image;
158 LoadAlbumScreenShotImageOutput image_output;
159 Result result =
160 manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options);
161 result = TranslateResult(result);
162
163 if (image.size() > image_buffer_size) {
164 result = ResultWorkMemoryError;
165 }
166
167 if (result.IsSuccess()) {
168 ctx.WriteBuffer(image_output, 0);
169 ctx.WriteBuffer(image, 1);
170 }
171
172 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(result);
174}
175
176void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
177 IPC::RequestParser rp{ctx};
178 const auto file_id{rp.PopRaw<AlbumFileId>()};
179 const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
180
181 LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
182 file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
183
184 std::vector<u8> image(ctx.GetWriteBufferSize(1));
185 LoadAlbumScreenShotImageOutput image_output;
186 Result result =
187 manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options);
188 result = TranslateResult(result);
189
190 if (result.IsSuccess()) {
191 ctx.WriteBuffer(image_output, 0);
192 ctx.WriteBuffer(image, 1);
193 }
194
195 IPC::ResponseBuilder rb{ctx, 2};
196 rb.Push(result);
197}
198
199Result IAlbumAccessorService::TranslateResult(Result in_result) {
200 if (in_result.IsSuccess()) {
201 return in_result;
202 }
203
204 if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
205 if (in_result.description - 0x514 < 100) {
206 return ResultInvalidFileData;
207 }
208 if (in_result.description - 0x5dc < 100) {
209 return ResultInvalidFileData;
210 }
211
212 if (in_result.description - 0x578 < 100) {
213 if (in_result == ResultFileCountLimit) {
214 return ResultUnknown22;
215 }
216 return ResultUnknown25;
217 }
218
219 if (in_result.raw < ResultUnknown1801.raw) {
220 if (in_result == ResultUnknown1202) {
221 return ResultUnknown810;
222 }
223 if (in_result == ResultUnknown1203) {
224 return ResultUnknown810;
225 }
226 if (in_result == ResultUnknown1701) {
227 return ResultUnknown5;
228 }
229 } else if (in_result.raw < ResultUnknown1803.raw) {
230 if (in_result == ResultUnknown1801) {
231 return ResultUnknown5;
232 }
233 if (in_result == ResultUnknown1802) {
234 return ResultUnknown6;
235 }
236 } else {
237 if (in_result == ResultUnknown1803) {
238 return ResultUnknown7;
239 }
240 if (in_result == ResultUnknown1804) {
241 return ResultOutOfRange;
242 }
243 }
244 return ResultUnknown1024;
245 }
246
247 if (in_result.module == ErrorModule::FS) {
248 if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) ||
249 (((in_result.description - 3000) >> 3) < 0x271)) {
250 // TODO: Translate FS error
251 return in_result;
252 }
253 }
254
255 return in_result;
256}
78 257
79} // namespace Service::Capture 258} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h
index 98a21a5ad..c90cff71e 100644
--- a/src/core/hle/service/caps/caps_a.h
+++ b/src/core/hle/service/caps/caps_a.h
@@ -10,11 +10,26 @@ class System;
10} 10}
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13class AlbumManager;
13 14
14class CAPS_A final : public ServiceFramework<CAPS_A> { 15class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> {
15public: 16public:
16 explicit CAPS_A(Core::System& system_); 17 explicit IAlbumAccessorService(Core::System& system_,
17 ~CAPS_A() override; 18 std::shared_ptr<AlbumManager> album_manager);
19 ~IAlbumAccessorService() override;
20
21private:
22 void DeleteAlbumFile(HLERequestContext& ctx);
23 void IsAlbumMounted(HLERequestContext& ctx);
24 void Unknown18(HLERequestContext& ctx);
25 void GetAlbumFileListEx0(HLERequestContext& ctx);
26 void GetAutoSavingStorage(HLERequestContext& ctx);
27 void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
28 void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
29
30 Result TranslateResult(Result in_result);
31
32 std::shared_ptr<AlbumManager> manager = nullptr;
18}; 33};
19 34
20} // namespace Service::Capture 35} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp
index fc77e35cd..1e7fe6474 100644
--- a/src/core/hle/service/caps/caps_c.cpp
+++ b/src/core/hle/service/caps/caps_c.cpp
@@ -3,53 +3,21 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/hle/service/caps/caps_c.h" 5#include "core/hle/service/caps/caps_c.h"
6#include "core/hle/service/caps/caps_manager.h"
7#include "core/hle/service/caps/caps_result.h"
8#include "core/hle/service/caps/caps_types.h"
6#include "core/hle/service/ipc_helpers.h" 9#include "core/hle/service/ipc_helpers.h"
7 10
8namespace Service::Capture { 11namespace Service::Capture {
9 12
10class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { 13IAlbumControlService::IAlbumControlService(Core::System& system_,
11public: 14 std::shared_ptr<AlbumManager> album_manager)
12 explicit IAlbumControlSession(Core::System& system_) 15 : ServiceFramework{system_, "caps:c"}, manager{album_manager} {
13 : ServiceFramework{system_, "IAlbumControlSession"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {2001, nullptr, "OpenAlbumMovieReadStream"},
17 {2002, nullptr, "CloseAlbumMovieReadStream"},
18 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
19 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
20 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
21 {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
22 {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
23 {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
24 {2401, nullptr, "OpenAlbumMovieWriteStream"},
25 {2402, nullptr, "FinishAlbumMovieWriteStream"},
26 {2403, nullptr, "CommitAlbumMovieWriteStream"},
27 {2404, nullptr, "DiscardAlbumMovieWriteStream"},
28 {2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"},
29 {2406, nullptr, "CommitAlbumMovieWriteStreamEx"},
30 {2411, nullptr, "StartAlbumMovieWriteStreamDataSection"},
31 {2412, nullptr, "EndAlbumMovieWriteStreamDataSection"},
32 {2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"},
33 {2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"},
34 {2421, nullptr, "ReadDataFromAlbumMovieWriteStream"},
35 {2422, nullptr, "WriteDataToAlbumMovieWriteStream"},
36 {2424, nullptr, "WriteMetaToAlbumMovieWriteStream"},
37 {2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"},
38 {2433, nullptr, "GetAlbumMovieWriteStreamDataSize"},
39 {2434, nullptr, "SetAlbumMovieWriteStreamDataSize"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44 }
45};
46
47CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
48 // clang-format off 16 // clang-format off
49 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
50 {1, nullptr, "CaptureRawImage"}, 18 {1, nullptr, "CaptureRawImage"},
51 {2, nullptr, "CaptureRawImageWithTimeout"}, 19 {2, nullptr, "CaptureRawImageWithTimeout"},
52 {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"}, 20 {33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"},
53 {1001, nullptr, "RequestTakingScreenShot"}, 21 {1001, nullptr, "RequestTakingScreenShot"},
54 {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, 22 {1002, nullptr, "RequestTakingScreenShotWithTimeout"},
55 {1011, nullptr, "NotifyTakingScreenShotRefused"}, 23 {1011, nullptr, "NotifyTakingScreenShotRefused"},
@@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
72 RegisterHandlers(functions); 40 RegisterHandlers(functions);
73} 41}
74 42
75CAPS_C::~CAPS_C() = default; 43IAlbumControlService::~IAlbumControlService() = default;
76 44
77void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) { 45void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) {
78 IPC::RequestParser rp{ctx}; 46 IPC::RequestParser rp{ctx};
79 const auto library_version{rp.Pop<u64>()}; 47 const auto library_version{rp.Pop<u64>()};
80 const auto applet_resource_user_id{rp.Pop<u64>()}; 48 const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h
index 537b3a2e3..92ba242db 100644
--- a/src/core/hle/service/caps/caps_c.h
+++ b/src/core/hle/service/caps/caps_c.h
@@ -10,14 +10,18 @@ class System;
10} 10}
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13class AlbumManager;
13 14
14class CAPS_C final : public ServiceFramework<CAPS_C> { 15class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
15public: 16public:
16 explicit CAPS_C(Core::System& system_); 17 explicit IAlbumControlService(Core::System& system_,
17 ~CAPS_C() override; 18 std::shared_ptr<AlbumManager> album_manager);
19 ~IAlbumControlService() override;
18 20
19private: 21private:
20 void SetShimLibraryVersion(HLERequestContext& ctx); 22 void SetShimLibraryVersion(HLERequestContext& ctx);
23
24 std::shared_ptr<AlbumManager> manager = nullptr;
21}; 25};
22 26
23} // namespace Service::Capture 27} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
new file mode 100644
index 000000000..2df6a930a
--- /dev/null
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -0,0 +1,342 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <sstream>
5#include <stb_image.h>
6#include <stb_image_resize.h>
7
8#include "common/fs/file.h"
9#include "common/fs/path_util.h"
10#include "common/logging/log.h"
11#include "core/hle/service/caps/caps_manager.h"
12#include "core/hle/service/caps/caps_result.h"
13
14namespace Service::Capture {
15
16AlbumManager::AlbumManager() {}
17
18AlbumManager::~AlbumManager() = default;
19
20Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) {
21 if (file_id.storage > AlbumStorage::Sd) {
22 return ResultInvalidStorage;
23 }
24
25 if (!is_mounted) {
26 return ResultIsNotMounted;
27 }
28
29 std::filesystem::path path;
30 const auto result = GetFile(path, file_id);
31
32 if (result.IsError()) {
33 return result;
34 }
35
36 if (!Common::FS::RemoveFile(path)) {
37 return ResultFileNotFound;
38 }
39
40 return ResultSuccess;
41}
42
43Result AlbumManager::IsAlbumMounted(AlbumStorage storage) {
44 if (storage > AlbumStorage::Sd) {
45 return ResultInvalidStorage;
46 }
47
48 is_mounted = true;
49
50 if (storage == AlbumStorage::Sd) {
51 FindScreenshots();
52 }
53
54 return is_mounted ? ResultSuccess : ResultIsNotMounted;
55}
56
57Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
58 u8 flags) const {
59 if (storage > AlbumStorage::Sd) {
60 return ResultInvalidStorage;
61 }
62
63 if (!is_mounted) {
64 return ResultIsNotMounted;
65 }
66
67 for (auto& [file_id, path] : album_files) {
68 if (file_id.storage != storage) {
69 continue;
70 }
71 if (out_entries.size() >= SdAlbumFileLimit) {
72 break;
73 }
74
75 const auto entry_size = Common::FS::GetSize(path);
76 out_entries.push_back({
77 .entry_size = entry_size,
78 .file_id = file_id,
79 });
80 }
81
82 return ResultSuccess;
83}
84
85Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
86 ContentType contex_type, AlbumFileDateTime start_date,
87 AlbumFileDateTime end_date, u64 aruid) const {
88 if (!is_mounted) {
89 return ResultIsNotMounted;
90 }
91
92 for (auto& [file_id, path] : album_files) {
93 if (file_id.type != contex_type) {
94 continue;
95 }
96
97 if (file_id.date > start_date) {
98 continue;
99 }
100
101 if (file_id.date < end_date) {
102 continue;
103 }
104
105 if (out_entries.size() >= SdAlbumFileLimit) {
106 break;
107 }
108
109 const auto entry_size = Common::FS::GetSize(path);
110 ApplicationAlbumFileEntry entry{.entry =
111 {
112 .size = entry_size,
113 .hash{},
114 .datetime = file_id.date,
115 .storage = file_id.storage,
116 .content = contex_type,
117 .unknown = 1,
118 },
119 .datetime = file_id.date,
120 .unknown = {}};
121 out_entries.push_back(entry);
122 }
123
124 return ResultSuccess;
125}
126
127Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const {
128 out_is_autosaving = false;
129 return ResultSuccess;
130}
131
132Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
133 std::vector<u8>& out_image,
134 const AlbumFileId& file_id,
135 const ScreenShotDecodeOption& decoder_options) const {
136 if (file_id.storage > AlbumStorage::Sd) {
137 return ResultInvalidStorage;
138 }
139
140 if (!is_mounted) {
141 return ResultIsNotMounted;
142 }
143
144 out_image_output = {
145 .width = 1280,
146 .height = 720,
147 .attribute =
148 {
149 .unknown_0{},
150 .orientation = AlbumImageOrientation::None,
151 .unknown_1{},
152 .unknown_2{},
153 },
154 };
155
156 std::filesystem::path path;
157 const auto result = GetFile(path, file_id);
158
159 if (result.IsError()) {
160 return result;
161 }
162
163 out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
164
165 return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
166 +static_cast<int>(out_image_output.height), decoder_options.flags);
167}
168
169Result AlbumManager::LoadAlbumScreenShotThumbnail(
170 LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image,
171 const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
172 if (file_id.storage > AlbumStorage::Sd) {
173 return ResultInvalidStorage;
174 }
175
176 if (!is_mounted) {
177 return ResultIsNotMounted;
178 }
179
180 out_image_output = {
181 .width = 320,
182 .height = 180,
183 .attribute =
184 {
185 .unknown_0{},
186 .orientation = AlbumImageOrientation::None,
187 .unknown_1{},
188 .unknown_2{},
189 },
190 };
191
192 std::filesystem::path path;
193 const auto result = GetFile(path, file_id);
194
195 if (result.IsError()) {
196 return result;
197 }
198
199 out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
200
201 return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
202 +static_cast<int>(out_image_output.height), decoder_options.flags);
203}
204
205Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
206 const auto file = album_files.find(file_id);
207
208 if (file == album_files.end()) {
209 return ResultFileNotFound;
210 }
211
212 out_path = file->second;
213 return ResultSuccess;
214}
215
216void AlbumManager::FindScreenshots() {
217 is_mounted = false;
218 album_files.clear();
219
220 // TODO: Swap this with a blocking operation.
221 const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir);
222 Common::FS::IterateDirEntries(
223 screenshots_dir,
224 [this](const std::filesystem::path& full_path) {
225 AlbumEntry entry;
226 if (GetAlbumEntry(entry, full_path).IsError()) {
227 return true;
228 }
229 while (album_files.contains(entry.file_id)) {
230 if (++entry.file_id.date.unique_id == 0) {
231 break;
232 }
233 }
234 album_files[entry.file_id] = full_path;
235 return true;
236 },
237 Common::FS::DirEntryFilter::File);
238
239 is_mounted = true;
240}
241
242Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const {
243 std::istringstream line_stream(path.filename().string());
244 std::string date;
245 std::string application;
246 std::string time;
247
248 // Parse filename to obtain entry properties
249 std::getline(line_stream, application, '_');
250 std::getline(line_stream, date, '_');
251 std::getline(line_stream, time, '_');
252
253 std::istringstream date_stream(date);
254 std::istringstream time_stream(time);
255 std::string year;
256 std::string month;
257 std::string day;
258 std::string hour;
259 std::string minute;
260 std::string second;
261
262 std::getline(date_stream, year, '-');
263 std::getline(date_stream, month, '-');
264 std::getline(date_stream, day, '-');
265
266 std::getline(time_stream, hour, '-');
267 std::getline(time_stream, minute, '-');
268 std::getline(time_stream, second, '-');
269
270 try {
271 out_entry = {
272 .entry_size = 1,
273 .file_id{
274 .application_id = static_cast<u64>(std::stoll(application, 0, 16)),
275 .date =
276 {
277 .year = static_cast<u16>(std::stoi(year)),
278 .month = static_cast<u8>(std::stoi(month)),
279 .day = static_cast<u8>(std::stoi(day)),
280 .hour = static_cast<u8>(std::stoi(hour)),
281 .minute = static_cast<u8>(std::stoi(minute)),
282 .second = static_cast<u8>(std::stoi(second)),
283 .unique_id = 0,
284 },
285 .storage = AlbumStorage::Sd,
286 .type = ContentType::Screenshot,
287 .unknown = 1,
288 },
289 };
290 } catch (const std::invalid_argument&) {
291 return ResultUnknown;
292 } catch (const std::out_of_range&) {
293 return ResultUnknown;
294 } catch (const std::exception&) {
295 return ResultUnknown;
296 }
297
298 return ResultSuccess;
299}
300
301Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
302 int width, int height, ScreenShotDecoderFlag flag) const {
303 if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) {
304 return ResultUnknown;
305 }
306
307 const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read,
308 Common::FS::FileType::BinaryFile};
309
310 std::vector<u8> raw_file(db_file.GetSize());
311 if (db_file.Read(raw_file) != raw_file.size()) {
312 return ResultUnknown;
313 }
314
315 int filter_flag = STBIR_FILTER_DEFAULT;
316 int original_width, original_height, color_channels;
317 const auto dbi_image =
318 stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width,
319 &original_height, &color_channels, STBI_rgb_alpha);
320
321 if (dbi_image == nullptr) {
322 return ResultUnknown;
323 }
324
325 switch (flag) {
326 case ScreenShotDecoderFlag::EnableFancyUpsampling:
327 filter_flag = STBIR_FILTER_TRIANGLE;
328 break;
329 case ScreenShotDecoderFlag::EnableBlockSmoothing:
330 filter_flag = STBIR_FILTER_BOX;
331 break;
332 default:
333 filter_flag = STBIR_FILTER_DEFAULT;
334 break;
335 }
336
337 stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width,
338 height, 0, STBI_rgb_alpha, 3, filter_flag);
339
340 return ResultSuccess;
341}
342} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h
new file mode 100644
index 000000000..8337c655c
--- /dev/null
+++ b/src/core/hle/service/caps/caps_manager.h
@@ -0,0 +1,72 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <unordered_map>
7
8#include "common/fs/fs.h"
9#include "core/hle/result.h"
10#include "core/hle/service/caps/caps_types.h"
11
12namespace Core {
13class System;
14}
15
16namespace std {
17// Hash used to create lists from AlbumFileId data
18template <>
19struct hash<Service::Capture::AlbumFileId> {
20 size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept {
21 u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8);
22 hash_value ^= (static_cast<u64>(pad_id.date.month) << 7);
23 hash_value ^= (static_cast<u64>(pad_id.date.day) << 6);
24 hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5);
25 hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4);
26 hash_value ^= (static_cast<u64>(pad_id.date.second) << 3);
27 hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2);
28 hash_value ^= (static_cast<u64>(pad_id.storage) << 1);
29 hash_value ^= static_cast<u64>(pad_id.type);
30 return static_cast<size_t>(hash_value);
31 }
32};
33
34} // namespace std
35
36namespace Service::Capture {
37
38class AlbumManager {
39public:
40 explicit AlbumManager();
41 ~AlbumManager();
42
43 Result DeleteAlbumFile(const AlbumFileId& file_id);
44 Result IsAlbumMounted(AlbumStorage storage);
45 Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
46 u8 flags) const;
47 Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
48 ContentType contex_type, AlbumFileDateTime start_date,
49 AlbumFileDateTime end_date, u64 aruid) const;
50 Result GetAutoSavingStorage(bool& out_is_autosaving) const;
51 Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
52 std::vector<u8>& out_image, const AlbumFileId& file_id,
53 const ScreenShotDecodeOption& decoder_options) const;
54 Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
55 std::vector<u8>& out_image, const AlbumFileId& file_id,
56 const ScreenShotDecodeOption& decoder_options) const;
57
58private:
59 static constexpr std::size_t NandAlbumFileLimit = 1000;
60 static constexpr std::size_t SdAlbumFileLimit = 10000;
61
62 void FindScreenshots();
63 Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const;
64 Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
65 Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
66 int height, ScreenShotDecoderFlag flag) const;
67
68 bool is_mounted{};
69 std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
70};
71
72} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_result.h b/src/core/hle/service/caps/caps_result.h
new file mode 100644
index 000000000..c65e5fb9a
--- /dev/null
+++ b/src/core/hle/service/caps/caps_result.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::Capture {
9
10constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3);
11constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
12constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
13constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
14constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
15constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12);
16constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
17constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
18constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
19constexpr Result ResultUnknown22(ErrorModule::Capture, 22);
20constexpr Result ResultFileNotFound(ErrorModule::Capture, 23);
21constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24);
22constexpr Result ResultUnknown25(ErrorModule::Capture, 25);
23constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30);
24constexpr Result ResultUnknown810(ErrorModule::Capture, 810);
25constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024);
26constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202);
27constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203);
28constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401);
29constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701);
30constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801);
31constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802);
32constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803);
33constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804);
34
35} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp
index 395b13da7..6117cb7c6 100644
--- a/src/core/hle/service/caps/caps_sc.cpp
+++ b/src/core/hle/service/caps/caps_sc.cpp
@@ -5,7 +5,8 @@
5 5
6namespace Service::Capture { 6namespace Service::Capture {
7 7
8CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { 8IScreenShotControlService::IScreenShotControlService(Core::System& system_)
9 : ServiceFramework{system_, "caps:sc"} {
9 // clang-format off 10 // clang-format off
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {1, nullptr, "CaptureRawImage"}, 12 {1, nullptr, "CaptureRawImage"},
@@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
34 RegisterHandlers(functions); 35 RegisterHandlers(functions);
35} 36}
36 37
37CAPS_SC::~CAPS_SC() = default; 38IScreenShotControlService::~IScreenShotControlService() = default;
38 39
39} // namespace Service::Capture 40} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h
index e5600f6d7..d555f4979 100644
--- a/src/core/hle/service/caps/caps_sc.h
+++ b/src/core/hle/service/caps/caps_sc.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13 13
14class CAPS_SC final : public ServiceFramework<CAPS_SC> { 14class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> {
15public: 15public:
16 explicit CAPS_SC(Core::System& system_); 16 explicit IScreenShotControlService(Core::System& system_);
17 ~CAPS_SC() override; 17 ~IScreenShotControlService() override;
18}; 18};
19 19
20} // namespace Service::Capture 20} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp
index 62b9edd41..d0d1b5425 100644
--- a/src/core/hle/service/caps/caps_ss.cpp
+++ b/src/core/hle/service/caps/caps_ss.cpp
@@ -5,7 +5,8 @@
5 5
6namespace Service::Capture { 6namespace Service::Capture {
7 7
8CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { 8IScreenShotService::IScreenShotService(Core::System& system_)
9 : ServiceFramework{system_, "caps:ss"} {
9 // clang-format off 10 // clang-format off
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {201, nullptr, "SaveScreenShot"}, 12 {201, nullptr, "SaveScreenShot"},
@@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
21 RegisterHandlers(functions); 22 RegisterHandlers(functions);
22} 23}
23 24
24CAPS_SS::~CAPS_SS() = default; 25IScreenShotService::~IScreenShotService() = default;
25 26
26} // namespace Service::Capture 27} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h
index 718ade485..381e44fd4 100644
--- a/src/core/hle/service/caps/caps_ss.h
+++ b/src/core/hle/service/caps/caps_ss.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13 13
14class CAPS_SS final : public ServiceFramework<CAPS_SS> { 14class IScreenShotService final : public ServiceFramework<IScreenShotService> {
15public: 15public:
16 explicit CAPS_SS(Core::System& system_); 16 explicit IScreenShotService(Core::System& system_);
17 ~CAPS_SS() override; 17 ~IScreenShotService() override;
18}; 18};
19 19
20} // namespace Service::Capture 20} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
index 3b11cc95c..cad173dc7 100644
--- a/src/core/hle/service/caps/caps_su.cpp
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -7,10 +7,11 @@
7 7
8namespace Service::Capture { 8namespace Service::Capture {
9 9
10CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { 10IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
11 : ServiceFramework{system_, "caps:su"} {
11 // clang-format off 12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, 14 {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
14 {201, nullptr, "SaveScreenShot"}, 15 {201, nullptr, "SaveScreenShot"},
15 {203, nullptr, "SaveScreenShotEx0"}, 16 {203, nullptr, "SaveScreenShotEx0"},
16 {205, nullptr, "SaveScreenShotEx1"}, 17 {205, nullptr, "SaveScreenShotEx1"},
@@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
21 RegisterHandlers(functions); 22 RegisterHandlers(functions);
22} 23}
23 24
24CAPS_SU::~CAPS_SU() = default; 25IScreenShotApplicationService::~IScreenShotApplicationService() = default;
25 26
26void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) { 27void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
27 IPC::RequestParser rp{ctx}; 28 IPC::RequestParser rp{ctx};
28 const auto library_version{rp.Pop<u64>()}; 29 const auto library_version{rp.Pop<u64>()};
29 const auto applet_resource_user_id{rp.Pop<u64>()}; 30 const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h
index c6398858d..647e3059d 100644
--- a/src/core/hle/service/caps/caps_su.h
+++ b/src/core/hle/service/caps/caps_su.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13 13
14class CAPS_SU final : public ServiceFramework<CAPS_SU> { 14class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
15public: 15public:
16 explicit CAPS_SU(Core::System& system_); 16 explicit IScreenShotApplicationService(Core::System& system_);
17 ~CAPS_SU() override; 17 ~IScreenShotApplicationService() override;
18 18
19private: 19private:
20 void SetShimLibraryVersion(HLERequestContext& ctx); 20 void SetShimLibraryVersion(HLERequestContext& ctx);
diff --git a/src/core/hle/service/caps/caps_types.h b/src/core/hle/service/caps/caps_types.h
new file mode 100644
index 000000000..bf6061273
--- /dev/null
+++ b/src/core/hle/service/caps/caps_types.h
@@ -0,0 +1,184 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::Capture {
10
11// This is nn::album::ImageOrientation
12enum class AlbumImageOrientation {
13 None,
14 Rotate90,
15 Rotate180,
16 Rotate270,
17};
18
19// This is nn::album::AlbumReportOption
20enum class AlbumReportOption : s32 {
21 Disable,
22 Enable,
23};
24
25enum class ContentType : u8 {
26 Screenshot = 0,
27 Movie = 1,
28 ExtraMovie = 3,
29};
30
31enum class AlbumStorage : u8 {
32 Nand,
33 Sd,
34};
35
36enum class ScreenShotDecoderFlag : u64 {
37 None = 0,
38 EnableFancyUpsampling = 1 << 0,
39 EnableBlockSmoothing = 1 << 1,
40};
41
42// This is nn::capsrv::AlbumFileDateTime
43struct AlbumFileDateTime {
44 u16 year{};
45 u8 month{};
46 u8 day{};
47 u8 hour{};
48 u8 minute{};
49 u8 second{};
50 u8 unique_id{};
51
52 friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
53 friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
54 if (a.year > b.year) {
55 return true;
56 }
57 if (a.month > b.month) {
58 return true;
59 }
60 if (a.day > b.day) {
61 return true;
62 }
63 if (a.hour > b.hour) {
64 return true;
65 }
66 if (a.minute > b.minute) {
67 return true;
68 }
69 return a.second > b.second;
70 };
71 friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
72 if (a.year < b.year) {
73 return true;
74 }
75 if (a.month < b.month) {
76 return true;
77 }
78 if (a.day < b.day) {
79 return true;
80 }
81 if (a.hour < b.hour) {
82 return true;
83 }
84 if (a.minute < b.minute) {
85 return true;
86 }
87 return a.second < b.second;
88 };
89};
90static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
91
92// This is nn::album::AlbumEntry
93struct AlbumFileEntry {
94 u64 size{}; // Size of the entry
95 u64 hash{}; // AES256 with hardcoded key over AlbumEntry
96 AlbumFileDateTime datetime{};
97 AlbumStorage storage{};
98 ContentType content{};
99 INSERT_PADDING_BYTES(5);
100 u8 unknown{}; // Set to 1 on official SW
101};
102static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
103
104struct AlbumFileId {
105 u64 application_id{};
106 AlbumFileDateTime date{};
107 AlbumStorage storage{};
108 ContentType type{};
109 INSERT_PADDING_BYTES(0x5);
110 u8 unknown{};
111
112 friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default;
113};
114static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size");
115
116// This is nn::capsrv::AlbumEntry
117struct AlbumEntry {
118 u64 entry_size{};
119 AlbumFileId file_id{};
120};
121static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
122
123// This is nn::capsrv::ApplicationAlbumEntry
124struct ApplicationAlbumEntry {
125 u64 size{}; // Size of the entry
126 u64 hash{}; // AES256 with hardcoded key over AlbumEntry
127 AlbumFileDateTime datetime{};
128 AlbumStorage storage{};
129 ContentType content{};
130 INSERT_PADDING_BYTES(5);
131 u8 unknown{1}; // Set to 1 on official SW
132};
133static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
134
135// This is nn::capsrv::ApplicationAlbumFileEntry
136struct ApplicationAlbumFileEntry {
137 ApplicationAlbumEntry entry{};
138 AlbumFileDateTime datetime{};
139 u64 unknown{};
140};
141static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
142 "ApplicationAlbumFileEntry has incorrect size.");
143
144struct ApplicationData {
145 std::array<u8, 0x400> data{};
146 u32 data_size{};
147};
148static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
149
150struct ScreenShotAttribute {
151 u32 unknown_0{};
152 AlbumImageOrientation orientation{};
153 u32 unknown_1{};
154 u32 unknown_2{};
155 INSERT_PADDING_BYTES(0x30);
156};
157static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
158
159struct ScreenShotDecodeOption {
160 ScreenShotDecoderFlag flags{};
161 INSERT_PADDING_BYTES(0x18);
162};
163static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
164
165struct LoadAlbumScreenShotImageOutput {
166 s64 width{};
167 s64 height{};
168 ScreenShotAttribute attribute{};
169 INSERT_PADDING_BYTES(0x400);
170};
171static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
172 "LoadAlbumScreenShotImageOutput is an invalid size");
173
174struct LoadAlbumScreenShotImageOutputForApplication {
175 s64 width{};
176 s64 height{};
177 ScreenShotAttribute attribute{};
178 ApplicationData data{};
179 INSERT_PADDING_BYTES(0xAC);
180};
181static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500,
182 "LoadAlbumScreenShotImageOutput is an invalid size");
183
184} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index bffe0f8d0..260f25490 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -2,45 +2,29 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/hle/service/caps/caps.h" 5#include "core/hle/service/caps/caps_manager.h"
6#include "core/hle/service/caps/caps_types.h"
6#include "core/hle/service/caps/caps_u.h" 7#include "core/hle/service/caps/caps_u.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8 9
9namespace Service::Capture { 10namespace Service::Capture {
10 11
11class IAlbumAccessorApplicationSession final 12IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
12 : public ServiceFramework<IAlbumAccessorApplicationSession> { 13 std::shared_ptr<AlbumManager> album_manager)
13public: 14 : ServiceFramework{system_, "caps:u"}, manager{album_manager} {
14 explicit IAlbumAccessorApplicationSession(Core::System& system_)
15 : ServiceFramework{system_, "IAlbumAccessorApplicationSession"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {2001, nullptr, "OpenAlbumMovieReadStream"},
19 {2002, nullptr, "CloseAlbumMovieReadStream"},
20 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
21 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
22 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27 }
28};
29
30CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
31 // clang-format off 15 // clang-format off
32 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
33 {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"}, 17 {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
34 {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, 18 {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
35 {103, nullptr, "DeleteAlbumContentsFileForApplication"}, 19 {103, nullptr, "DeleteAlbumFileByAruid"},
36 {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, 20 {104, nullptr, "GetAlbumFileSizeByAruid"},
37 {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, 21 {105, nullptr, "DeleteAlbumFileByAruidForDebug"},
38 {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, 22 {110, nullptr, "LoadAlbumScreenShotImageByAruid"},
39 {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, 23 {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
40 {130, nullptr, "PrecheckToCreateContentsForApplication"}, 24 {130, nullptr, "PrecheckToCreateContentsByAruid"},
41 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, 25 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
42 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, 26 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
43 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, 27 {142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
44 {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, 28 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
45 {144, nullptr, "GetAllAlbumFileList3AaeAruid"}, 29 {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
46 {60002, nullptr, "OpenAccessorSessionForApplication"}, 30 {60002, nullptr, "OpenAccessorSessionForApplication"},
@@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
50 RegisterHandlers(functions); 34 RegisterHandlers(functions);
51} 35}
52 36
53CAPS_U::~CAPS_U() = default; 37IAlbumApplicationService::~IAlbumApplicationService() = default;
54 38
55void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) { 39void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
56 IPC::RequestParser rp{ctx}; 40 IPC::RequestParser rp{ctx};
57 const auto library_version{rp.Pop<u64>()}; 41 const auto library_version{rp.Pop<u64>()};
58 const auto applet_resource_user_id{rp.Pop<u64>()}; 42 const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -64,10 +48,7 @@ void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
64 rb.Push(ResultSuccess); 48 rb.Push(ResultSuccess);
65} 49}
66 50
67void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) { 51void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
68 // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
69 // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
70 // output entries (which is copied to a s32 by official SW).
71 IPC::RequestParser rp{ctx}; 52 IPC::RequestParser rp{ctx};
72 const auto pid{rp.Pop<s32>()}; 53 const auto pid{rp.Pop<s32>()};
73 const auto content_type{rp.PopEnum<ContentType>()}; 54 const auto content_type{rp.PopEnum<ContentType>()};
@@ -75,26 +56,49 @@ void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
75 const auto end_posix_time{rp.Pop<s64>()}; 56 const auto end_posix_time{rp.Pop<s64>()};
76 const auto applet_resource_user_id{rp.Pop<u64>()}; 57 const auto applet_resource_user_id{rp.Pop<u64>()};
77 58
78 // TODO: Update this when we implement the album. 59 LOG_WARNING(Service_Capture,
79 // Currently we do not have a method of accessing album entries, set this to 0 for now. 60 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
80 constexpr u32 total_entries_1{}; 61 "end_posix_time={}, applet_resource_user_id={}",
81 constexpr u32 total_entries_2{}; 62 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
63
64 // TODO: Translate posix to DateTime
65
66 std::vector<ApplicationAlbumFileEntry> entries;
67 const Result result =
68 manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
82 69
83 LOG_WARNING( 70 if (!entries.empty()) {
84 Service_Capture, 71 ctx.WriteBuffer(entries);
85 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " 72 }
86 "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
87 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
88 total_entries_1, total_entries_2);
89 73
90 IPC::ResponseBuilder rb{ctx, 4}; 74 IPC::ResponseBuilder rb{ctx, 4};
91 rb.Push(ResultSuccess); 75 rb.Push(result);
92 rb.Push(total_entries_1); 76 rb.Push<u64>(entries.size());
93 rb.Push(total_entries_2);
94} 77}
95 78
96void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { 79void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
97 GetAlbumContentsFileListForApplication(ctx); 80 IPC::RequestParser rp{ctx};
81 const auto pid{rp.Pop<s32>()};
82 const auto content_type{rp.PopEnum<ContentType>()};
83 const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()};
84 const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()};
85 const auto applet_resource_user_id{rp.Pop<u64>()};
86
87 LOG_WARNING(Service_Capture,
88 "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
89 content_type, applet_resource_user_id);
90
91 std::vector<ApplicationAlbumFileEntry> entries;
92 const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time,
93 end_date_time, applet_resource_user_id);
94
95 if (!entries.empty()) {
96 ctx.WriteBuffer(entries);
97 }
98
99 IPC::ResponseBuilder rb{ctx, 4};
100 rb.Push(result);
101 rb.Push<u64>(entries.size());
98} 102}
99 103
100} // namespace Service::Capture 104} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h
index e8dd037d7..9458c128e 100644
--- a/src/core/hle/service/caps/caps_u.h
+++ b/src/core/hle/service/caps/caps_u.h
@@ -10,16 +10,20 @@ class System;
10} 10}
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13class AlbumManager;
13 14
14class CAPS_U final : public ServiceFramework<CAPS_U> { 15class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> {
15public: 16public:
16 explicit CAPS_U(Core::System& system_); 17 explicit IAlbumApplicationService(Core::System& system_,
17 ~CAPS_U() override; 18 std::shared_ptr<AlbumManager> album_manager);
19 ~IAlbumApplicationService() override;
18 20
19private: 21private:
20 void SetShimLibraryVersion(HLERequestContext& ctx); 22 void SetShimLibraryVersion(HLERequestContext& ctx);
21 void GetAlbumContentsFileListForApplication(HLERequestContext& ctx); 23 void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx);
22 void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); 24 void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
25
26 std::shared_ptr<AlbumManager> manager = nullptr;
23}; 27};
24 28
25} // namespace Service::Capture 29} // namespace Service::Capture
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 21b06d10b..22dc55a6d 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -545,6 +545,16 @@ void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
545 } 545 }
546} 546}
547 547
548void IGeneralService::IsAnyForegroundRequestAccepted(HLERequestContext& ctx) {
549 const bool is_accepted{};
550
551 LOG_WARNING(Service_NIFM, "(STUBBED) called, is_accepted={}", is_accepted);
552
553 IPC::ResponseBuilder rb{ctx, 3};
554 rb.Push(ResultSuccess);
555 rb.Push<u8>(is_accepted);
556}
557
548IGeneralService::IGeneralService(Core::System& system_) 558IGeneralService::IGeneralService(Core::System& system_)
549 : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} { 559 : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
550 // clang-format off 560 // clang-format off
@@ -569,7 +579,7 @@ IGeneralService::IGeneralService(Core::System& system_)
569 {19, nullptr, "SetEthernetCommunicationEnabled"}, 579 {19, nullptr, "SetEthernetCommunicationEnabled"},
570 {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"}, 580 {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
571 {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"}, 581 {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
572 {22, nullptr, "IsAnyForegroundRequestAccepted"}, 582 {22, &IGeneralService::IsAnyForegroundRequestAccepted, "IsAnyForegroundRequestAccepted"},
573 {23, nullptr, "PutToSleep"}, 583 {23, nullptr, "PutToSleep"},
574 {24, nullptr, "WakeUp"}, 584 {24, nullptr, "WakeUp"},
575 {25, nullptr, "GetSsidListVersion"}, 585 {25, nullptr, "GetSsidListVersion"},
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index ae99c4695..b74b66438 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -35,6 +35,7 @@ private:
35 void GetInternetConnectionStatus(HLERequestContext& ctx); 35 void GetInternetConnectionStatus(HLERequestContext& ctx);
36 void IsEthernetCommunicationEnabled(HLERequestContext& ctx); 36 void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
37 void IsAnyInternetRequestAccepted(HLERequestContext& ctx); 37 void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
38 void IsAnyForegroundRequestAccepted(HLERequestContext& ctx);
38 39
39 Network::RoomNetwork& network; 40 Network::RoomNetwork& network;
40}; 41};
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 6e0baf0be..f9e0e272d 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -7,6 +7,7 @@
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 8#include "core/file_sys/patch_manager.h"
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
10#include "core/hle/service/filesystem/filesystem.h"
10#include "core/hle/service/glue/glue_manager.h" 11#include "core/hle/service/glue/glue_manager.h"
11#include "core/hle/service/ipc_helpers.h" 12#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/ns/errors.h" 13#include "core/hle/service/ns/errors.h"
@@ -502,8 +503,8 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
502 static const FunctionInfo functions[] = { 503 static const FunctionInfo functions[] = {
503 {11, nullptr, "CalculateApplicationOccupiedSize"}, 504 {11, nullptr, "CalculateApplicationOccupiedSize"},
504 {43, nullptr, "CheckSdCardMountStatus"}, 505 {43, nullptr, "CheckSdCardMountStatus"},
505 {47, nullptr, "GetTotalSpaceSize"}, 506 {47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"},
506 {48, nullptr, "GetFreeSpaceSize"}, 507 {48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"},
507 {600, nullptr, "CountApplicationContentMeta"}, 508 {600, nullptr, "CountApplicationContentMeta"},
508 {601, nullptr, "ListApplicationContentMetaStatus"}, 509 {601, nullptr, "ListApplicationContentMetaStatus"},
509 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, 510 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
@@ -516,6 +517,28 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
516 517
517IContentManagementInterface::~IContentManagementInterface() = default; 518IContentManagementInterface::~IContentManagementInterface() = default;
518 519
520void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) {
521 IPC::RequestParser rp{ctx};
522 const auto storage{rp.PopEnum<FileSys::StorageId>()};
523
524 LOG_INFO(Service_Capture, "called, storage={}", storage);
525
526 IPC::ResponseBuilder rb{ctx, 4};
527 rb.Push(ResultSuccess);
528 rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage));
529}
530
531void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) {
532 IPC::RequestParser rp{ctx};
533 const auto storage{rp.PopEnum<FileSys::StorageId>()};
534
535 LOG_INFO(Service_Capture, "called, storage={}", storage);
536
537 IPC::ResponseBuilder rb{ctx, 4};
538 rb.Push(ResultSuccess);
539 rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage));
540}
541
519IDocumentInterface::IDocumentInterface(Core::System& system_) 542IDocumentInterface::IDocumentInterface(Core::System& system_)
520 : ServiceFramework{system_, "IDocumentInterface"} { 543 : ServiceFramework{system_, "IDocumentInterface"} {
521 // clang-format off 544 // clang-format off
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 175dad780..34d2a45dc 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -48,6 +48,10 @@ class IContentManagementInterface final : public ServiceFramework<IContentManage
48public: 48public:
49 explicit IContentManagementInterface(Core::System& system_); 49 explicit IContentManagementInterface(Core::System& system_);
50 ~IContentManagementInterface() override; 50 ~IContentManagementInterface() override;
51
52private:
53 void GetTotalSpaceSize(HLERequestContext& ctx);
54 void GetFreeSpaceSize(HLERequestContext& ctx);
51}; 55};
52 56
53class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { 57class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
index 5db1703d1..938330dd0 100644
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ b/src/core/hle/service/pctl/pctl_module.cpp
@@ -33,7 +33,7 @@ public:
33 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, 33 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
34 {1002, nullptr, "ConfirmLaunchApplicationPermission"}, 34 {1002, nullptr, "ConfirmLaunchApplicationPermission"},
35 {1003, nullptr, "ConfirmResumeApplicationPermission"}, 35 {1003, nullptr, "ConfirmResumeApplicationPermission"},
36 {1004, nullptr, "ConfirmSnsPostPermission"}, 36 {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
37 {1005, nullptr, "ConfirmSystemSettingsPermission"}, 37 {1005, nullptr, "ConfirmSystemSettingsPermission"},
38 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"}, 38 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
39 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, 39 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
@@ -236,6 +236,13 @@ private:
236 states.free_communication = true; 236 states.free_communication = true;
237 } 237 }
238 238
239 void ConfirmSnsPostPermission(HLERequestContext& ctx) {
240 LOG_WARNING(Service_PCTL, "(STUBBED) called");
241
242 IPC::ResponseBuilder rb{ctx, 2};
243 rb.Push(Error::ResultNoFreeCommunication);
244 }
245
239 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) { 246 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
240 const bool is_temporary_unlocked = false; 247 const bool is_temporary_unlocked = false;
241 248
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 89361fa3f..5427758c1 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1560,6 +1560,7 @@ void GMainWindow::ConnectMenuEvents() {
1560 // Tools 1560 // Tools
1561 connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, 1561 connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
1562 ReinitializeKeyBehavior::Warning)); 1562 ReinitializeKeyBehavior::Warning));
1563 connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
1563 connect_menu(ui->action_Load_Cabinet_Nickname_Owner, 1564 connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
1564 [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); }); 1565 [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
1565 connect_menu(ui->action_Load_Cabinet_Eraser, 1566 connect_menu(ui->action_Load_Cabinet_Eraser,
@@ -1597,6 +1598,7 @@ void GMainWindow::UpdateMenuState() {
1597 }; 1598 };
1598 1599
1599 const std::array applet_actions{ 1600 const std::array applet_actions{
1601 ui->action_Load_Album,
1600 ui->action_Load_Cabinet_Nickname_Owner, 1602 ui->action_Load_Cabinet_Nickname_Owner,
1601 ui->action_Load_Cabinet_Eraser, 1603 ui->action_Load_Cabinet_Eraser,
1602 ui->action_Load_Cabinet_Restorer, 1604 ui->action_Load_Cabinet_Restorer,
@@ -4224,6 +4226,29 @@ void GMainWindow::OnToggleStatusBar() {
4224 statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); 4226 statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
4225} 4227}
4226 4228
4229void GMainWindow::OnAlbum() {
4230 constexpr u64 AlbumId = 0x010000000000100Dull;
4231 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4232 if (!bis_system) {
4233 QMessageBox::warning(this, tr("No firmware available"),
4234 tr("Please install the firmware to use the Album applet."));
4235 return;
4236 }
4237
4238 auto album_nca = bis_system->GetEntry(AlbumId, FileSys::ContentRecordType::Program);
4239 if (!album_nca) {
4240 QMessageBox::warning(this, tr("Album Applet"),
4241 tr("Album applet is not available. Please reinstall firmware."));
4242 return;
4243 }
4244
4245 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer);
4246
4247 const auto filename = QString::fromStdString(album_nca->GetFullPath());
4248 UISettings::values.roms_path = QFileInfo(filename).path();
4249 BootGame(filename);
4250}
4251
4227void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { 4252void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4228 constexpr u64 CabinetId = 0x0100000000001002ull; 4253 constexpr u64 CabinetId = 0x0100000000001002ull;
4229 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4254 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index c1872ecd4..2346eb3bd 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -374,6 +374,7 @@ private slots:
374 void ResetWindowSize720(); 374 void ResetWindowSize720();
375 void ResetWindowSize900(); 375 void ResetWindowSize900();
376 void ResetWindowSize1080(); 376 void ResetWindowSize1080();
377 void OnAlbum();
377 void OnCabinet(Service::NFP::CabinetMode mode); 378 void OnCabinet(Service::NFP::CabinetMode mode);
378 void OnMiiEdit(); 379 void OnMiiEdit();
379 void OnCaptureScreenshot(); 380 void OnCaptureScreenshot();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 31c3de9ef..88684ffb5 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -160,6 +160,7 @@
160 <addaction name="action_Verify_installed_contents"/> 160 <addaction name="action_Verify_installed_contents"/>
161 <addaction name="separator"/> 161 <addaction name="separator"/>
162 <addaction name="menu_cabinet_applet"/> 162 <addaction name="menu_cabinet_applet"/>
163 <addaction name="action_Load_Album"/>
163 <addaction name="action_Load_Mii_Edit"/> 164 <addaction name="action_Load_Mii_Edit"/>
164 <addaction name="separator"/> 165 <addaction name="separator"/>
165 <addaction name="action_Capture_Screenshot"/> 166 <addaction name="action_Capture_Screenshot"/>
@@ -380,6 +381,11 @@
380 <string>&amp;Capture Screenshot</string> 381 <string>&amp;Capture Screenshot</string>
381 </property> 382 </property>
382 </action> 383 </action>
384 <action name="action_Load_Album">
385 <property name="text">
386 <string>Open &amp;Album</string>
387 </property>
388 </action>
383 <action name="action_Load_Cabinet_Nickname_Owner"> 389 <action name="action_Load_Cabinet_Nickname_Owner">
384 <property name="text"> 390 <property name="text">
385 <string>&amp;Set Nickname and Owner</string> 391 <string>&amp;Set Nickname and Owner</string>