service: caps: Implement album manager and reorganize service
This commit is contained in:
		| @@ -466,14 +466,18 @@ add_library(core STATIC | |||||||
|     hle/service/caps/caps_a.h |     hle/service/caps/caps_a.h | ||||||
|     hle/service/caps/caps_c.cpp |     hle/service/caps/caps_c.cpp | ||||||
|     hle/service/caps/caps_c.h |     hle/service/caps/caps_c.h | ||||||
|     hle/service/caps/caps_u.cpp |     hle/service/caps/caps_manager.cpp | ||||||
|     hle/service/caps/caps_u.h |     hle/service/caps/caps_manager.h | ||||||
|  |     hle/service/caps/caps_result.h | ||||||
|     hle/service/caps/caps_sc.cpp |     hle/service/caps/caps_sc.cpp | ||||||
|     hle/service/caps/caps_sc.h |     hle/service/caps/caps_sc.h | ||||||
|     hle/service/caps/caps_ss.cpp |     hle/service/caps/caps_ss.cpp | ||||||
|     hle/service/caps/caps_ss.h |     hle/service/caps/caps_ss.h | ||||||
|     hle/service/caps/caps_su.cpp |     hle/service/caps/caps_su.cpp | ||||||
|     hle/service/caps/caps_su.h |     hle/service/caps/caps_su.h | ||||||
|  |     hle/service/caps/caps_types.h | ||||||
|  |     hle/service/caps/caps_u.cpp | ||||||
|  |     hle/service/caps/caps_u.h | ||||||
|     hle/service/erpt/erpt.cpp |     hle/service/erpt/erpt.cpp | ||||||
|     hle/service/erpt/erpt.h |     hle/service/erpt/erpt.h | ||||||
|     hle/service/es/es.cpp |     hle/service/es/es.cpp | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ | |||||||
| #include "core/hle/service/apm/apm_controller.h" | #include "core/hle/service/apm/apm_controller.h" | ||||||
| #include "core/hle/service/apm/apm_interface.h" | #include "core/hle/service/apm/apm_interface.h" | ||||||
| #include "core/hle/service/bcat/backend/backend.h" | #include "core/hle/service/bcat/backend/backend.h" | ||||||
| #include "core/hle/service/caps/caps.h" | #include "core/hle/service/caps/caps_types.h" | ||||||
| #include "core/hle/service/filesystem/filesystem.h" | #include "core/hle/service/filesystem/filesystem.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
| #include "core/hle/service/ns/ns.h" | #include "core/hle/service/ns/ns.h" | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
| #include "core/hle/service/caps/caps.h" | #include "core/hle/service/caps/caps.h" | ||||||
| #include "core/hle/service/caps/caps_a.h" | #include "core/hle/service/caps/caps_a.h" | ||||||
| #include "core/hle/service/caps/caps_c.h" | #include "core/hle/service/caps/caps_c.h" | ||||||
|  | #include "core/hle/service/caps/caps_manager.h" | ||||||
| #include "core/hle/service/caps/caps_sc.h" | #include "core/hle/service/caps/caps_sc.h" | ||||||
| #include "core/hle/service/caps/caps_ss.h" | #include "core/hle/service/caps/caps_ss.h" | ||||||
| #include "core/hle/service/caps/caps_su.h" | #include "core/hle/service/caps/caps_su.h" | ||||||
| @@ -15,13 +16,21 @@ namespace Service::Capture { | |||||||
|  |  | ||||||
| void LoopProcess(Core::System& system) { | void LoopProcess(Core::System& system) { | ||||||
|     auto server_manager = std::make_unique<ServerManager>(system); |     auto server_manager = std::make_unique<ServerManager>(system); | ||||||
|  |     auto album_manager = std::make_shared<AlbumManager>(); | ||||||
|  |  | ||||||
|  |     server_manager->RegisterNamedService( | ||||||
|  |         "caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager)); | ||||||
|  |     server_manager->RegisterNamedService( | ||||||
|  |         "caps:c", std::make_shared<IAlbumControlService>(system, album_manager)); | ||||||
|  |     server_manager->RegisterNamedService( | ||||||
|  |         "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager)); | ||||||
|  |  | ||||||
|  |     server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system)); | ||||||
|  |     server_manager->RegisterNamedService("caps:sc", | ||||||
|  |                                          std::make_shared<IScreenShotControlService>(system)); | ||||||
|  |     server_manager->RegisterNamedService("caps:su", | ||||||
|  |                                          std::make_shared<IScreenShotApplicationService>(system)); | ||||||
|  |  | ||||||
|     server_manager->RegisterNamedService("caps:a", std::make_shared<IAlbumAccessorService>(system)); |  | ||||||
|     server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system)); |  | ||||||
|     server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system)); |  | ||||||
|     server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system)); |  | ||||||
|     server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system)); |  | ||||||
|     server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system)); |  | ||||||
|     ServerManager::RunServer(std::move(server_manager)); |     ServerManager::RunServer(std::move(server_manager)); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,93 +3,12 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "common/common_funcs.h" |  | ||||||
| #include "common/common_types.h" |  | ||||||
|  |  | ||||||
| namespace Core { | namespace Core { | ||||||
| class System; | class System; | ||||||
| } | } | ||||||
|  |  | ||||||
| namespace Service::SM { |  | ||||||
| class ServiceManager; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| enum class AlbumImageOrientation { |  | ||||||
|     Orientation0 = 0, |  | ||||||
|     Orientation1 = 1, |  | ||||||
|     Orientation2 = 2, |  | ||||||
|     Orientation3 = 3, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| enum class AlbumReportOption : s32 { |  | ||||||
|     Disable = 0, |  | ||||||
|     Enable = 1, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| enum class ContentType : u8 { |  | ||||||
|     Screenshot = 0, |  | ||||||
|     Movie = 1, |  | ||||||
|     ExtraMovie = 3, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| enum class AlbumStorage : u8 { |  | ||||||
|     NAND = 0, |  | ||||||
|     SD = 1, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| struct AlbumFileDateTime { |  | ||||||
|     s16 year{}; |  | ||||||
|     s8 month{}; |  | ||||||
|     s8 day{}; |  | ||||||
|     s8 hour{}; |  | ||||||
|     s8 minute{}; |  | ||||||
|     s8 second{}; |  | ||||||
|     s8 uid{}; |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size."); |  | ||||||
|  |  | ||||||
| struct AlbumEntry { |  | ||||||
|     u64 size{}; |  | ||||||
|     u64 application_id{}; |  | ||||||
|     AlbumFileDateTime datetime{}; |  | ||||||
|     AlbumStorage storage{}; |  | ||||||
|     ContentType content{}; |  | ||||||
|     INSERT_PADDING_BYTES(6); |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size."); |  | ||||||
|  |  | ||||||
| struct AlbumFileEntry { |  | ||||||
|     u64 size{}; // Size of the entry |  | ||||||
|     u64 hash{}; // AES256 with hardcoded key over AlbumEntry |  | ||||||
|     AlbumFileDateTime datetime{}; |  | ||||||
|     AlbumStorage storage{}; |  | ||||||
|     ContentType content{}; |  | ||||||
|     INSERT_PADDING_BYTES(5); |  | ||||||
|     u8 unknown{1}; // Set to 1 on official SW |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size."); |  | ||||||
|  |  | ||||||
| struct ApplicationAlbumEntry { |  | ||||||
|     u64 size{}; // Size of the entry |  | ||||||
|     u64 hash{}; // AES256 with hardcoded key over AlbumEntry |  | ||||||
|     AlbumFileDateTime datetime{}; |  | ||||||
|     AlbumStorage storage{}; |  | ||||||
|     ContentType content{}; |  | ||||||
|     INSERT_PADDING_BYTES(5); |  | ||||||
|     u8 unknown{1}; // Set to 1 on official SW |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size."); |  | ||||||
|  |  | ||||||
| struct ApplicationAlbumFileEntry { |  | ||||||
|     ApplicationAlbumEntry entry{}; |  | ||||||
|     AlbumFileDateTime datetime{}; |  | ||||||
|     u64 unknown{}; |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, |  | ||||||
|               "ApplicationAlbumFileEntry has incorrect size."); |  | ||||||
|  |  | ||||||
| void LoopProcess(Core::System& system); | void LoopProcess(Core::System& system); | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -1,40 +1,18 @@ | |||||||
| // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
| #include <sstream> | #include "common/logging/log.h" | ||||||
| #include <stb_image.h> |  | ||||||
| #include <stb_image_resize.h> |  | ||||||
|  |  | ||||||
| #include "common/fs/file.h" |  | ||||||
| #include "common/fs/path_util.h" |  | ||||||
| #include "core/hle/service/caps/caps_a.h" | #include "core/hle/service/caps/caps_a.h" | ||||||
|  | #include "core/hle/service/caps/caps_manager.h" | ||||||
|  | #include "core/hle/service/caps/caps_result.h" | ||||||
|  | #include "core/hle/service/caps/caps_types.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { | IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, | ||||||
| public: |                                              std::shared_ptr<AlbumManager> album_manager) | ||||||
|     explicit IAlbumAccessorSession(Core::System& system_) |     : ServiceFramework{system_, "caps:a"}, manager{album_manager} { | ||||||
|         : ServiceFramework{system_, "IAlbumAccessorSession"} { |  | ||||||
|         // clang-format off |  | ||||||
|         static const FunctionInfo functions[] = { |  | ||||||
|             {2001, nullptr, "OpenAlbumMovieReadStream"}, |  | ||||||
|             {2002, nullptr, "CloseAlbumMovieReadStream"}, |  | ||||||
|             {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, |  | ||||||
|             {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, |  | ||||||
|             {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, |  | ||||||
|             {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, |  | ||||||
|             {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, |  | ||||||
|             {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, |  | ||||||
|         }; |  | ||||||
|         // clang-format on |  | ||||||
|  |  | ||||||
|         RegisterHandlers(functions); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| IAlbumAccessorService::IAlbumAccessorService(Core::System& system_) |  | ||||||
|     : ServiceFramework{system_, "caps:a"} { |  | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0, nullptr, "GetAlbumFileCount"}, |         {0, nullptr, "GetAlbumFileCount"}, | ||||||
| @@ -91,30 +69,25 @@ void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) { | |||||||
|     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}", |     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}", | ||||||
|              file_id.application_id, file_id.storage, file_id.type); |              file_id.application_id, file_id.storage, file_id.type); | ||||||
|  |  | ||||||
|     if (file_id.storage == AlbumStorage::Sd) { |     Result result = manager->DeleteAlbumFile(file_id); | ||||||
|         if (!Common::FS::RemoveFile(sd_image_paths[file_id.date.unique_id])) { |     result = TranslateResult(result); | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |  | ||||||
|             rb.Push(ResultUnknown); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
| } | } | ||||||
|  |  | ||||||
| void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) { | void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto storage{rp.PopEnum<AlbumStorage>()}; |     const auto storage{rp.PopEnum<AlbumStorage>()}; | ||||||
|  |  | ||||||
|     LOG_INFO(Service_Capture, "called, storage={}, is_mounted={}", storage, is_mounted); |     LOG_INFO(Service_Capture, "called, storage={}", storage); | ||||||
|  |  | ||||||
|     if (storage == AlbumStorage::Sd) { |     Result result = manager->IsAlbumMounted(storage); | ||||||
|         FindScreenshots(); |     const bool is_mounted = result.IsSuccess(); | ||||||
|     } |     result = TranslateResult(result); | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
|     rb.Push<u8>(is_mounted); |     rb.Push<u8>(is_mounted); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -141,38 +114,34 @@ void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) { | |||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto storage{rp.PopEnum<AlbumStorage>()}; |     const auto storage{rp.PopEnum<AlbumStorage>()}; | ||||||
|     const auto flags{rp.Pop<u8>()}; |     const auto flags{rp.Pop<u8>()}; | ||||||
|  |     const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()}; | ||||||
|  |  | ||||||
|     LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags); |     LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags); | ||||||
|  |  | ||||||
|     std::vector<AlbumEntry> entries{}; |     std::vector<AlbumEntry> entries; | ||||||
|  |     Result result = manager->GetAlbumFileList(entries, storage, flags); | ||||||
|  |     result = TranslateResult(result); | ||||||
|  |  | ||||||
|     if (storage == AlbumStorage::Sd) { |     entries.resize(std::min(album_entry_size, entries.size())); | ||||||
|         AlbumEntry entry; |  | ||||||
|         for (u8 i = 0; i < static_cast<u8>(sd_image_paths.size()); i++) { |  | ||||||
|             if (GetAlbumEntry(entry, sd_image_paths[i]).IsError()) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|             entry.file_id.date.unique_id = i; |  | ||||||
|             entries.push_back(entry); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (!entries.empty()) { |     if (!entries.empty()) { | ||||||
|         ctx.WriteBuffer(entries); |         ctx.WriteBuffer(entries); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
|     rb.Push(entries.size()); |     rb.Push(entries.size()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) { | void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) { | ||||||
|     bool is_autosaving{}; |     LOG_WARNING(Service_Capture, "(STUBBED) called"); | ||||||
|  |  | ||||||
|     LOG_WARNING(Service_Capture, "(STUBBED) called, is_autosaving={}", is_autosaving); |     bool is_autosaving{}; | ||||||
|  |     Result result = manager->GetAutoSavingStorage(is_autosaving); | ||||||
|  |     result = TranslateResult(result); | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
|     rb.Push<u8>(is_autosaving); |     rb.Push<u8>(is_autosaving); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -180,35 +149,28 @@ void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) | |||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto file_id{rp.PopRaw<AlbumFileId>()}; |     const auto file_id{rp.PopRaw<AlbumFileId>()}; | ||||||
|     const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()}; |     const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()}; | ||||||
|  |     const auto image_buffer_size{ctx.GetWriteBufferSize(1)}; | ||||||
|  |  | ||||||
|     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", |     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", | ||||||
|              file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); |              file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); | ||||||
|  |  | ||||||
|     const LoadAlbumScreenShotImageOutput image_output{ |     std::vector<u8> image; | ||||||
|         .width = 1280, |     LoadAlbumScreenShotImageOutput image_output; | ||||||
|         .height = 720, |     Result result = | ||||||
|         .attribute = |         manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options); | ||||||
|             { |     result = TranslateResult(result); | ||||||
|                 .unknown_0{}, |  | ||||||
|                 .orientation = ScreenShotOrientation::None, |  | ||||||
|                 .unknown_1{}, |  | ||||||
|                 .unknown_2{}, |  | ||||||
|             }, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     std::vector<u8> image(image_output.height * image_output.width * STBI_rgb_alpha); |     if (image.size() > image_buffer_size) { | ||||||
|  |         result = ResultWorkMemoryError; | ||||||
|     if (file_id.storage == AlbumStorage::Sd) { |  | ||||||
|         LoadImage(image, sd_image_paths[file_id.date.unique_id], |  | ||||||
|                   static_cast<int>(image_output.width), static_cast<int>(image_output.height), |  | ||||||
|                   decoder_options.flags); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.WriteBuffer(image_output, 0); |     if (result.IsSuccess()) { | ||||||
|     ctx.WriteBuffer(image, 1); |         ctx.WriteBuffer(image_output, 0); | ||||||
|  |         ctx.WriteBuffer(image, 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
| } | } | ||||||
|  |  | ||||||
| void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) { | void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) { | ||||||
| @@ -219,157 +181,78 @@ void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestConte | |||||||
|     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", |     LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", | ||||||
|              file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); |              file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); | ||||||
|  |  | ||||||
|     const LoadAlbumScreenShotImageOutput image_output{ |     std::vector<u8> image(ctx.GetWriteBufferSize(1)); | ||||||
|         .width = 320, |     LoadAlbumScreenShotImageOutput image_output; | ||||||
|         .height = 180, |     Result result = | ||||||
|         .attribute = |         manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options); | ||||||
|             { |     result = TranslateResult(result); | ||||||
|                 .unknown_0{}, |  | ||||||
|                 .orientation = ScreenShotOrientation::None, |  | ||||||
|                 .unknown_1{}, |  | ||||||
|                 .unknown_2{}, |  | ||||||
|             }, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     std::vector<u8> image(image_output.height * image_output.width * STBI_rgb_alpha); |     if (result.IsSuccess()) { | ||||||
|  |         ctx.WriteBuffer(image_output, 0); | ||||||
|     if (file_id.storage == AlbumStorage::Sd) { |         ctx.WriteBuffer(image, 1); | ||||||
|         LoadImage(image, sd_image_paths[file_id.date.unique_id], |  | ||||||
|                   static_cast<int>(image_output.width), static_cast<int>(image_output.height), |  | ||||||
|                   decoder_options.flags); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ctx.WriteBuffer(image_output, 0); |  | ||||||
|     ctx.WriteBuffer(image, 1); |  | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
| } | } | ||||||
|  |  | ||||||
| void IAlbumAccessorService::FindScreenshots() { | Result IAlbumAccessorService::TranslateResult(Result in_result) { | ||||||
|     is_mounted = false; |     if (in_result.IsSuccess()) { | ||||||
|     sd_image_paths.clear(); |         return in_result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // TODO: Swap this with a blocking operation. |     if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) { | ||||||
|     const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir); |         if (in_result.description - 0x514 < 100) { | ||||||
|     Common::FS::IterateDirEntries( |             return ResultInvalidFileData; | ||||||
|         screenshots_dir, |         } | ||||||
|         [this](const std::filesystem::path& full_path) { |         if (in_result.description - 0x5dc < 100) { | ||||||
|             AlbumEntry entry; |             return ResultInvalidFileData; | ||||||
|             // TODO: Implement proper indexing to allow more images |         } | ||||||
|             if (sd_image_paths.size() > 0xFF) { |  | ||||||
|                 return true; |         if (in_result.description - 0x578 < 100) { | ||||||
|  |             if (in_result == ResultFileCountLimit) { | ||||||
|  |                 return ResultUnknown22; | ||||||
|             } |             } | ||||||
|             if (GetAlbumEntry(entry, full_path).IsSuccess()) { |             return ResultUnknown25; | ||||||
|                 sd_image_paths.push_back(full_path); |         } | ||||||
|  |  | ||||||
|  |         if (in_result.raw < ResultUnknown1801.raw) { | ||||||
|  |             if (in_result == ResultUnknown1202) { | ||||||
|  |                 return ResultUnknown810; | ||||||
|             } |             } | ||||||
|             return true; |             if (in_result == ResultUnknown1203) { | ||||||
|         }, |                 return ResultUnknown810; | ||||||
|         Common::FS::DirEntryFilter::File); |             } | ||||||
|  |             if (in_result == ResultUnknown1701) { | ||||||
|     is_mounted = true; |                 return ResultUnknown5; | ||||||
| } |             } | ||||||
|  |         } else if (in_result.raw < ResultUnknown1803.raw) { | ||||||
| Result IAlbumAccessorService::GetAlbumEntry(AlbumEntry& out_entry, |             if (in_result == ResultUnknown1801) { | ||||||
|                                             const std::filesystem::path& path) { |                 return ResultUnknown5; | ||||||
|     std::istringstream line_stream(path.filename().string()); |             } | ||||||
|     std::string date; |             if (in_result == ResultUnknown1802) { | ||||||
|     std::string application; |                 return ResultUnknown6; | ||||||
|     std::string time; |             } | ||||||
|  |         } else { | ||||||
|     // Parse filename to obtain entry properties |             if (in_result == ResultUnknown1803) { | ||||||
|     std::getline(line_stream, application, '_'); |                 return ResultUnknown7; | ||||||
|     std::getline(line_stream, date, '_'); |             } | ||||||
|     std::getline(line_stream, time, '_'); |             if (in_result == ResultUnknown1804) { | ||||||
|  |                 return ResultOutOfRange; | ||||||
|     std::istringstream date_stream(date); |             } | ||||||
|     std::istringstream time_stream(time); |         } | ||||||
|     std::string year; |         return ResultUnknown1024; | ||||||
|     std::string month; |  | ||||||
|     std::string day; |  | ||||||
|     std::string hour; |  | ||||||
|     std::string minute; |  | ||||||
|     std::string second; |  | ||||||
|  |  | ||||||
|     std::getline(date_stream, year, '-'); |  | ||||||
|     std::getline(date_stream, month, '-'); |  | ||||||
|     std::getline(date_stream, day, '-'); |  | ||||||
|  |  | ||||||
|     std::getline(time_stream, hour, '-'); |  | ||||||
|     std::getline(time_stream, minute, '-'); |  | ||||||
|     std::getline(time_stream, second, '-'); |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|         out_entry = { |  | ||||||
|             .entry_size = 1, |  | ||||||
|             .file_id{ |  | ||||||
|                 .application_id = static_cast<u64>(std::stoll(application, 0, 16)), |  | ||||||
|                 .date = |  | ||||||
|                     { |  | ||||||
|                         .year = static_cast<u16>(std::stoi(year)), |  | ||||||
|                         .month = static_cast<u8>(std::stoi(month)), |  | ||||||
|                         .day = static_cast<u8>(std::stoi(day)), |  | ||||||
|                         .hour = static_cast<u8>(std::stoi(hour)), |  | ||||||
|                         .minute = static_cast<u8>(std::stoi(minute)), |  | ||||||
|                         .second = static_cast<u8>(std::stoi(second)), |  | ||||||
|                         .unique_id = 0, |  | ||||||
|                     }, |  | ||||||
|                 .storage = AlbumStorage::Sd, |  | ||||||
|                 .type = ContentType::Screenshot, |  | ||||||
|                 .unknown = 1, |  | ||||||
|             }, |  | ||||||
|         }; |  | ||||||
|     } catch (const std::invalid_argument&) { |  | ||||||
|         return ResultUnknown; |  | ||||||
|     } catch (const std::out_of_range&) { |  | ||||||
|         return ResultUnknown; |  | ||||||
|     } catch (const std::exception&) { |  | ||||||
|         return ResultUnknown; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ResultSuccess; |     if (in_result.module == ErrorModule::FS) { | ||||||
| } |         if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) || | ||||||
|  |             (((in_result.description - 3000) >> 3) < 0x271)) { | ||||||
| Result IAlbumAccessorService::LoadImage(std::span<u8> out_image, const std::filesystem::path& path, |             // TODO: Translate FS error | ||||||
|                                         int width, int height, ScreenShotDecoderFlag flag) { |             return in_result; | ||||||
|     if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) { |         } | ||||||
|         return ResultUnknown; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read, |     return in_result; | ||||||
|                                      Common::FS::FileType::BinaryFile}; |  | ||||||
|  |  | ||||||
|     std::vector<u8> raw_file(db_file.GetSize()); |  | ||||||
|     if (db_file.Read(raw_file) != raw_file.size()) { |  | ||||||
|         return ResultUnknown; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     int filter_flag = STBIR_FILTER_DEFAULT; |  | ||||||
|     int original_width, original_height, color_channels; |  | ||||||
|     const auto dbi_image = |  | ||||||
|         stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width, |  | ||||||
|                               &original_height, &color_channels, STBI_rgb_alpha); |  | ||||||
|  |  | ||||||
|     if (dbi_image == nullptr) { |  | ||||||
|         return ResultUnknown; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     switch (flag) { |  | ||||||
|     case ScreenShotDecoderFlag::EnableFancyUpsampling: |  | ||||||
|         filter_flag = STBIR_FILTER_TRIANGLE; |  | ||||||
|         break; |  | ||||||
|     case ScreenShotDecoderFlag::EnableBlockSmoothing: |  | ||||||
|         filter_flag = STBIR_FILTER_BOX; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         filter_flag = STBIR_FILTER_DEFAULT; |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width, |  | ||||||
|                             height, 0, STBI_rgb_alpha, 3, filter_flag); |  | ||||||
|  |  | ||||||
|     return ResultSuccess; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "common/fs/fs.h" |  | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
|  |  | ||||||
| namespace Core { | namespace Core { | ||||||
| @@ -11,106 +10,15 @@ class System; | |||||||
| } | } | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  | class AlbumManager; | ||||||
|  |  | ||||||
| class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> { | class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> { | ||||||
| public: | public: | ||||||
|     explicit IAlbumAccessorService(Core::System& system_); |     explicit IAlbumAccessorService(Core::System& system_, | ||||||
|  |                                    std::shared_ptr<AlbumManager> album_manager); | ||||||
|     ~IAlbumAccessorService() override; |     ~IAlbumAccessorService() override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     enum class ContentType : u8 { |  | ||||||
|         Screenshot, |  | ||||||
|         Movie, |  | ||||||
|         ExtraMovie, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     enum class AlbumStorage : u8 { |  | ||||||
|         Nand, |  | ||||||
|         Sd, |  | ||||||
|  |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     enum class ScreenShotDecoderFlag : u64 { |  | ||||||
|         None = 0, |  | ||||||
|         EnableFancyUpsampling = 1 << 0, |  | ||||||
|         EnableBlockSmoothing = 1 << 1, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     enum class ScreenShotOrientation : u32 { |  | ||||||
|         None, |  | ||||||
|         Rotate90, |  | ||||||
|         Rotate180, |  | ||||||
|         Rotate270, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     struct ScreenShotAttribute { |  | ||||||
|         u32 unknown_0; |  | ||||||
|         ScreenShotOrientation orientation; |  | ||||||
|         u32 unknown_1; |  | ||||||
|         u32 unknown_2; |  | ||||||
|         INSERT_PADDING_BYTES(0x30); |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct ScreenShotDecodeOption { |  | ||||||
|         ScreenShotDecoderFlag flags; |  | ||||||
|         INSERT_PADDING_BYTES(0x18); |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(ScreenShotDecodeOption) == 0x20, |  | ||||||
|                   "ScreenShotDecodeOption is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct AlbumFileDateTime { |  | ||||||
|         u16 year; |  | ||||||
|         u8 month; |  | ||||||
|         u8 day; |  | ||||||
|         u8 hour; |  | ||||||
|         u8 minute; |  | ||||||
|         u8 second; |  | ||||||
|         u8 unique_id; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct AlbumFileId { |  | ||||||
|         u64 application_id; |  | ||||||
|         AlbumFileDateTime date; |  | ||||||
|         AlbumStorage storage; |  | ||||||
|         ContentType type; |  | ||||||
|         INSERT_PADDING_BYTES(0x5); |  | ||||||
|         u8 unknown; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct AlbumEntry { |  | ||||||
|         u64 entry_size; |  | ||||||
|         AlbumFileId file_id; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct ApplicationData { |  | ||||||
|         std::array<u8, 0x400> data; |  | ||||||
|         u32 data_size; |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct LoadAlbumScreenShotImageOutput { |  | ||||||
|         s64 width; |  | ||||||
|         s64 height; |  | ||||||
|         ScreenShotAttribute attribute; |  | ||||||
|         INSERT_PADDING_BYTES(0x400); |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450, |  | ||||||
|                   "LoadAlbumScreenShotImageOutput is an invalid size"); |  | ||||||
|  |  | ||||||
|     struct LoadAlbumScreenShotImageOutputForApplication { |  | ||||||
|         s64 width; |  | ||||||
|         s64 height; |  | ||||||
|         ScreenShotAttribute attribute; |  | ||||||
|         ApplicationData data; |  | ||||||
|         INSERT_PADDING_BYTES(0xAC); |  | ||||||
|     }; |  | ||||||
|     static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500, |  | ||||||
|                   "LoadAlbumScreenShotImageOutput is an invalid size"); |  | ||||||
|  |  | ||||||
|     void DeleteAlbumFile(HLERequestContext& ctx); |     void DeleteAlbumFile(HLERequestContext& ctx); | ||||||
|     void IsAlbumMounted(HLERequestContext& ctx); |     void IsAlbumMounted(HLERequestContext& ctx); | ||||||
|     void Unknown18(HLERequestContext& ctx); |     void Unknown18(HLERequestContext& ctx); | ||||||
| @@ -119,14 +27,9 @@ private: | |||||||
|     void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx); |     void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx); | ||||||
|     void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx); |     void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx); | ||||||
|  |  | ||||||
| private: |     Result TranslateResult(Result in_result); | ||||||
|     void FindScreenshots(); |  | ||||||
|     Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path); |  | ||||||
|     Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, |  | ||||||
|                      int height, ScreenShotDecoderFlag flag); |  | ||||||
|  |  | ||||||
|     bool is_mounted{}; |     std::shared_ptr<AlbumManager> manager = nullptr; | ||||||
|     std::vector<std::filesystem::path> sd_image_paths{}; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -3,53 +3,21 @@ | |||||||
|  |  | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/hle/service/caps/caps_c.h" | #include "core/hle/service/caps/caps_c.h" | ||||||
|  | #include "core/hle/service/caps/caps_manager.h" | ||||||
|  | #include "core/hle/service/caps/caps_result.h" | ||||||
|  | #include "core/hle/service/caps/caps_types.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { | IAlbumControlService::IAlbumControlService(Core::System& system_, | ||||||
| public: |                                            std::shared_ptr<AlbumManager> album_manager) | ||||||
|     explicit IAlbumControlSession(Core::System& system_) |     : ServiceFramework{system_, "caps:c"}, manager{album_manager} { | ||||||
|         : ServiceFramework{system_, "IAlbumControlSession"} { |  | ||||||
|         // clang-format off |  | ||||||
|         static const FunctionInfo functions[] = { |  | ||||||
|             {2001, nullptr, "OpenAlbumMovieReadStream"}, |  | ||||||
|             {2002, nullptr, "CloseAlbumMovieReadStream"}, |  | ||||||
|             {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, |  | ||||||
|             {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, |  | ||||||
|             {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, |  | ||||||
|             {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, |  | ||||||
|             {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, |  | ||||||
|             {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, |  | ||||||
|             {2401, nullptr, "OpenAlbumMovieWriteStream"}, |  | ||||||
|             {2402, nullptr, "FinishAlbumMovieWriteStream"}, |  | ||||||
|             {2403, nullptr, "CommitAlbumMovieWriteStream"}, |  | ||||||
|             {2404, nullptr, "DiscardAlbumMovieWriteStream"}, |  | ||||||
|             {2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"}, |  | ||||||
|             {2406, nullptr, "CommitAlbumMovieWriteStreamEx"}, |  | ||||||
|             {2411, nullptr, "StartAlbumMovieWriteStreamDataSection"}, |  | ||||||
|             {2412, nullptr, "EndAlbumMovieWriteStreamDataSection"}, |  | ||||||
|             {2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"}, |  | ||||||
|             {2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"}, |  | ||||||
|             {2421, nullptr, "ReadDataFromAlbumMovieWriteStream"}, |  | ||||||
|             {2422, nullptr, "WriteDataToAlbumMovieWriteStream"}, |  | ||||||
|             {2424, nullptr, "WriteMetaToAlbumMovieWriteStream"}, |  | ||||||
|             {2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"}, |  | ||||||
|             {2433, nullptr, "GetAlbumMovieWriteStreamDataSize"}, |  | ||||||
|             {2434, nullptr, "SetAlbumMovieWriteStreamDataSize"}, |  | ||||||
|         }; |  | ||||||
|         // clang-format on |  | ||||||
|  |  | ||||||
|         RegisterHandlers(functions); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} { |  | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {1, nullptr, "CaptureRawImage"}, |         {1, nullptr, "CaptureRawImage"}, | ||||||
|         {2, nullptr, "CaptureRawImageWithTimeout"}, |         {2, nullptr, "CaptureRawImageWithTimeout"}, | ||||||
|         {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"}, |         {33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||||
|         {1001, nullptr, "RequestTakingScreenShot"}, |         {1001, nullptr, "RequestTakingScreenShot"}, | ||||||
|         {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, |         {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, | ||||||
|         {1011, nullptr, "NotifyTakingScreenShotRefused"}, |         {1011, nullptr, "NotifyTakingScreenShotRefused"}, | ||||||
| @@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} { | |||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
|  |  | ||||||
| CAPS_C::~CAPS_C() = default; | IAlbumControlService::~IAlbumControlService() = default; | ||||||
|  |  | ||||||
| void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) { | void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto library_version{rp.Pop<u64>()}; |     const auto library_version{rp.Pop<u64>()}; | ||||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; |     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||||
|   | |||||||
| @@ -10,14 +10,18 @@ class System; | |||||||
| } | } | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  | class AlbumManager; | ||||||
|  |  | ||||||
| class CAPS_C final : public ServiceFramework<CAPS_C> { | class IAlbumControlService final : public ServiceFramework<IAlbumControlService> { | ||||||
| public: | public: | ||||||
|     explicit CAPS_C(Core::System& system_); |     explicit IAlbumControlService(Core::System& system_, | ||||||
|     ~CAPS_C() override; |                                   std::shared_ptr<AlbumManager> album_manager); | ||||||
|  |     ~IAlbumControlService() override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); |     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||||
|  |  | ||||||
|  |     std::shared_ptr<AlbumManager> manager = nullptr; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
							
								
								
									
										342
									
								
								src/core/hle/service/caps/caps_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								src/core/hle/service/caps/caps_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,342 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #include <sstream> | ||||||
|  | #include <stb_image.h> | ||||||
|  | #include <stb_image_resize.h> | ||||||
|  |  | ||||||
|  | #include "common/fs/file.h" | ||||||
|  | #include "common/fs/path_util.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "core/hle/service/caps/caps_manager.h" | ||||||
|  | #include "core/hle/service/caps/caps_result.h" | ||||||
|  |  | ||||||
|  | namespace Service::Capture { | ||||||
|  |  | ||||||
|  | AlbumManager::AlbumManager() {} | ||||||
|  |  | ||||||
|  | AlbumManager::~AlbumManager() = default; | ||||||
|  |  | ||||||
|  | Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) { | ||||||
|  |     if (file_id.storage > AlbumStorage::Sd) { | ||||||
|  |         return ResultInvalidStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!is_mounted) { | ||||||
|  |         return ResultIsNotMounted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::filesystem::path path; | ||||||
|  |     const auto result = GetFile(path, file_id); | ||||||
|  |  | ||||||
|  |     if (result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!Common::FS::RemoveFile(path)) { | ||||||
|  |         return ResultFileNotFound; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::IsAlbumMounted(AlbumStorage storage) { | ||||||
|  |     if (storage > AlbumStorage::Sd) { | ||||||
|  |         return ResultInvalidStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is_mounted = true; | ||||||
|  |  | ||||||
|  |     if (storage == AlbumStorage::Sd) { | ||||||
|  |         FindScreenshots(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return is_mounted ? ResultSuccess : ResultIsNotMounted; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, | ||||||
|  |                                       u8 flags) const { | ||||||
|  |     if (storage > AlbumStorage::Sd) { | ||||||
|  |         return ResultInvalidStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!is_mounted) { | ||||||
|  |         return ResultIsNotMounted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (auto& [file_id, path] : album_files) { | ||||||
|  |         if (file_id.storage != storage) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         if (out_entries.size() >= SdAlbumFileLimit) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const auto entry_size = Common::FS::GetSize(path); | ||||||
|  |         out_entries.push_back({ | ||||||
|  |             .entry_size = entry_size, | ||||||
|  |             .file_id = file_id, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | ||||||
|  |                                       ContentType contex_type, AlbumFileDateTime start_date, | ||||||
|  |                                       AlbumFileDateTime end_date, u64 aruid) const { | ||||||
|  |     if (!is_mounted) { | ||||||
|  |         return ResultIsNotMounted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (auto& [file_id, path] : album_files) { | ||||||
|  |         if (file_id.type != contex_type) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (file_id.date > start_date) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (file_id.date < end_date) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (out_entries.size() >= SdAlbumFileLimit) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const auto entry_size = Common::FS::GetSize(path); | ||||||
|  |         ApplicationAlbumFileEntry entry{.entry = | ||||||
|  |                                             { | ||||||
|  |                                                 .size = entry_size, | ||||||
|  |                                                 .hash{}, | ||||||
|  |                                                 .datetime = file_id.date, | ||||||
|  |                                                 .storage = file_id.storage, | ||||||
|  |                                                 .content = contex_type, | ||||||
|  |                                                 .unknown = 1, | ||||||
|  |                                             }, | ||||||
|  |                                         .datetime = file_id.date, | ||||||
|  |                                         .unknown = {}}; | ||||||
|  |         out_entries.push_back(entry); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const { | ||||||
|  |     out_is_autosaving = false; | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, | ||||||
|  |                                               std::vector<u8>& out_image, | ||||||
|  |                                               const AlbumFileId& file_id, | ||||||
|  |                                               const ScreenShotDecodeOption& decoder_options) const { | ||||||
|  |     if (file_id.storage > AlbumStorage::Sd) { | ||||||
|  |         return ResultInvalidStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!is_mounted) { | ||||||
|  |         return ResultIsNotMounted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out_image_output = { | ||||||
|  |         .width = 1280, | ||||||
|  |         .height = 720, | ||||||
|  |         .attribute = | ||||||
|  |             { | ||||||
|  |                 .unknown_0{}, | ||||||
|  |                 .orientation = AlbumImageOrientation::None, | ||||||
|  |                 .unknown_1{}, | ||||||
|  |                 .unknown_2{}, | ||||||
|  |             }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     std::filesystem::path path; | ||||||
|  |     const auto result = GetFile(path, file_id); | ||||||
|  |  | ||||||
|  |     if (result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); | ||||||
|  |  | ||||||
|  |     return LoadImage(out_image, path, static_cast<int>(out_image_output.width), | ||||||
|  |                      +static_cast<int>(out_image_output.height), decoder_options.flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::LoadAlbumScreenShotThumbnail( | ||||||
|  |     LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image, | ||||||
|  |     const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const { | ||||||
|  |     if (file_id.storage > AlbumStorage::Sd) { | ||||||
|  |         return ResultInvalidStorage; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!is_mounted) { | ||||||
|  |         return ResultIsNotMounted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out_image_output = { | ||||||
|  |         .width = 320, | ||||||
|  |         .height = 180, | ||||||
|  |         .attribute = | ||||||
|  |             { | ||||||
|  |                 .unknown_0{}, | ||||||
|  |                 .orientation = AlbumImageOrientation::None, | ||||||
|  |                 .unknown_1{}, | ||||||
|  |                 .unknown_2{}, | ||||||
|  |             }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     std::filesystem::path path; | ||||||
|  |     const auto result = GetFile(path, file_id); | ||||||
|  |  | ||||||
|  |     if (result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); | ||||||
|  |  | ||||||
|  |     return LoadImage(out_image, path, static_cast<int>(out_image_output.width), | ||||||
|  |                      +static_cast<int>(out_image_output.height), decoder_options.flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { | ||||||
|  |     const auto file = album_files.find(file_id); | ||||||
|  |  | ||||||
|  |     if (file == album_files.end()) { | ||||||
|  |         return ResultFileNotFound; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out_path = file->second; | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AlbumManager::FindScreenshots() { | ||||||
|  |     is_mounted = false; | ||||||
|  |     album_files.clear(); | ||||||
|  |  | ||||||
|  |     // TODO: Swap this with a blocking operation. | ||||||
|  |     const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir); | ||||||
|  |     Common::FS::IterateDirEntries( | ||||||
|  |         screenshots_dir, | ||||||
|  |         [this](const std::filesystem::path& full_path) { | ||||||
|  |             AlbumEntry entry; | ||||||
|  |             if (GetAlbumEntry(entry, full_path).IsError()) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             while (album_files.contains(entry.file_id)) { | ||||||
|  |                 if (++entry.file_id.date.unique_id == 0) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             album_files[entry.file_id] = full_path; | ||||||
|  |             return true; | ||||||
|  |         }, | ||||||
|  |         Common::FS::DirEntryFilter::File); | ||||||
|  |  | ||||||
|  |     is_mounted = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const { | ||||||
|  |     std::istringstream line_stream(path.filename().string()); | ||||||
|  |     std::string date; | ||||||
|  |     std::string application; | ||||||
|  |     std::string time; | ||||||
|  |  | ||||||
|  |     // Parse filename to obtain entry properties | ||||||
|  |     std::getline(line_stream, application, '_'); | ||||||
|  |     std::getline(line_stream, date, '_'); | ||||||
|  |     std::getline(line_stream, time, '_'); | ||||||
|  |  | ||||||
|  |     std::istringstream date_stream(date); | ||||||
|  |     std::istringstream time_stream(time); | ||||||
|  |     std::string year; | ||||||
|  |     std::string month; | ||||||
|  |     std::string day; | ||||||
|  |     std::string hour; | ||||||
|  |     std::string minute; | ||||||
|  |     std::string second; | ||||||
|  |  | ||||||
|  |     std::getline(date_stream, year, '-'); | ||||||
|  |     std::getline(date_stream, month, '-'); | ||||||
|  |     std::getline(date_stream, day, '-'); | ||||||
|  |  | ||||||
|  |     std::getline(time_stream, hour, '-'); | ||||||
|  |     std::getline(time_stream, minute, '-'); | ||||||
|  |     std::getline(time_stream, second, '-'); | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |         out_entry = { | ||||||
|  |             .entry_size = 1, | ||||||
|  |             .file_id{ | ||||||
|  |                 .application_id = static_cast<u64>(std::stoll(application, 0, 16)), | ||||||
|  |                 .date = | ||||||
|  |                     { | ||||||
|  |                         .year = static_cast<u16>(std::stoi(year)), | ||||||
|  |                         .month = static_cast<u8>(std::stoi(month)), | ||||||
|  |                         .day = static_cast<u8>(std::stoi(day)), | ||||||
|  |                         .hour = static_cast<u8>(std::stoi(hour)), | ||||||
|  |                         .minute = static_cast<u8>(std::stoi(minute)), | ||||||
|  |                         .second = static_cast<u8>(std::stoi(second)), | ||||||
|  |                         .unique_id = 0, | ||||||
|  |                     }, | ||||||
|  |                 .storage = AlbumStorage::Sd, | ||||||
|  |                 .type = ContentType::Screenshot, | ||||||
|  |                 .unknown = 1, | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |     } catch (const std::invalid_argument&) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } catch (const std::out_of_range&) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } catch (const std::exception&) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path, | ||||||
|  |                                int width, int height, ScreenShotDecoderFlag flag) const { | ||||||
|  |     if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read, | ||||||
|  |                                      Common::FS::FileType::BinaryFile}; | ||||||
|  |  | ||||||
|  |     std::vector<u8> raw_file(db_file.GetSize()); | ||||||
|  |     if (db_file.Read(raw_file) != raw_file.size()) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int filter_flag = STBIR_FILTER_DEFAULT; | ||||||
|  |     int original_width, original_height, color_channels; | ||||||
|  |     const auto dbi_image = | ||||||
|  |         stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width, | ||||||
|  |                               &original_height, &color_channels, STBI_rgb_alpha); | ||||||
|  |  | ||||||
|  |     if (dbi_image == nullptr) { | ||||||
|  |         return ResultUnknown; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     switch (flag) { | ||||||
|  |     case ScreenShotDecoderFlag::EnableFancyUpsampling: | ||||||
|  |         filter_flag = STBIR_FILTER_TRIANGLE; | ||||||
|  |         break; | ||||||
|  |     case ScreenShotDecoderFlag::EnableBlockSmoothing: | ||||||
|  |         filter_flag = STBIR_FILTER_BOX; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         filter_flag = STBIR_FILTER_DEFAULT; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width, | ||||||
|  |                             height, 0, STBI_rgb_alpha, 3, filter_flag); | ||||||
|  |  | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  | } // namespace Service::Capture | ||||||
							
								
								
									
										72
									
								
								src/core/hle/service/caps/caps_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/core/hle/service/caps/caps_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <unordered_map> | ||||||
|  |  | ||||||
|  | #include "common/fs/fs.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/caps/caps_types.h" | ||||||
|  |  | ||||||
|  | namespace Core { | ||||||
|  | class System; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace std { | ||||||
|  | // Hash used to create lists from AlbumFileId data | ||||||
|  | template <> | ||||||
|  | struct hash<Service::Capture::AlbumFileId> { | ||||||
|  |     size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept { | ||||||
|  |         u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.month) << 7); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.day) << 6); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.second) << 3); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2); | ||||||
|  |         hash_value ^= (static_cast<u64>(pad_id.storage) << 1); | ||||||
|  |         hash_value ^= static_cast<u64>(pad_id.type); | ||||||
|  |         return static_cast<size_t>(hash_value); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace std | ||||||
|  |  | ||||||
|  | namespace Service::Capture { | ||||||
|  |  | ||||||
|  | class AlbumManager { | ||||||
|  | public: | ||||||
|  |     explicit AlbumManager(); | ||||||
|  |     ~AlbumManager(); | ||||||
|  |  | ||||||
|  |     Result DeleteAlbumFile(const AlbumFileId& file_id); | ||||||
|  |     Result IsAlbumMounted(AlbumStorage storage); | ||||||
|  |     Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, | ||||||
|  |                             u8 flags) const; | ||||||
|  |     Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | ||||||
|  |                             ContentType contex_type, AlbumFileDateTime start_date, | ||||||
|  |                             AlbumFileDateTime end_date, u64 aruid) const; | ||||||
|  |     Result GetAutoSavingStorage(bool& out_is_autosaving) const; | ||||||
|  |     Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, | ||||||
|  |                                     std::vector<u8>& out_image, const AlbumFileId& file_id, | ||||||
|  |                                     const ScreenShotDecodeOption& decoder_options) const; | ||||||
|  |     Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output, | ||||||
|  |                                         std::vector<u8>& out_image, const AlbumFileId& file_id, | ||||||
|  |                                         const ScreenShotDecodeOption& decoder_options) const; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     static constexpr std::size_t NandAlbumFileLimit = 1000; | ||||||
|  |     static constexpr std::size_t SdAlbumFileLimit = 10000; | ||||||
|  |  | ||||||
|  |     void FindScreenshots(); | ||||||
|  |     Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const; | ||||||
|  |     Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; | ||||||
|  |     Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, | ||||||
|  |                      int height, ScreenShotDecoderFlag flag) const; | ||||||
|  |  | ||||||
|  |     bool is_mounted{}; | ||||||
|  |     std::unordered_map<AlbumFileId, std::filesystem::path> album_files; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Service::Capture | ||||||
							
								
								
									
										35
									
								
								src/core/hle/service/caps/caps_result.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/core/hle/service/caps/caps_result.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "core/hle/result.h" | ||||||
|  |  | ||||||
|  | namespace Service::Capture { | ||||||
|  |  | ||||||
|  | constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3); | ||||||
|  | constexpr Result ResultUnknown5(ErrorModule::Capture, 5); | ||||||
|  | constexpr Result ResultUnknown6(ErrorModule::Capture, 6); | ||||||
|  | constexpr Result ResultUnknown7(ErrorModule::Capture, 7); | ||||||
|  | constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); | ||||||
|  | constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); | ||||||
|  | constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); | ||||||
|  | constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); | ||||||
|  | constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); | ||||||
|  | constexpr Result ResultUnknown22(ErrorModule::Capture, 22); | ||||||
|  | constexpr Result ResultFileNotFound(ErrorModule::Capture, 23); | ||||||
|  | constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24); | ||||||
|  | constexpr Result ResultUnknown25(ErrorModule::Capture, 25); | ||||||
|  | constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30); | ||||||
|  | constexpr Result ResultUnknown810(ErrorModule::Capture, 810); | ||||||
|  | constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024); | ||||||
|  | constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202); | ||||||
|  | constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203); | ||||||
|  | constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401); | ||||||
|  | constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701); | ||||||
|  | constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801); | ||||||
|  | constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802); | ||||||
|  | constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803); | ||||||
|  | constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804); | ||||||
|  |  | ||||||
|  | } // namespace Service::Capture | ||||||
| @@ -5,7 +5,8 @@ | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { | IScreenShotControlService::IScreenShotControlService(Core::System& system_) | ||||||
|  |     : ServiceFramework{system_, "caps:sc"} { | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {1, nullptr, "CaptureRawImage"}, |         {1, nullptr, "CaptureRawImage"}, | ||||||
| @@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { | |||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
|  |  | ||||||
| CAPS_SC::~CAPS_SC() = default; | IScreenShotControlService::~IScreenShotControlService() = default; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ class System; | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class CAPS_SC final : public ServiceFramework<CAPS_SC> { | class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> { | ||||||
| public: | public: | ||||||
|     explicit CAPS_SC(Core::System& system_); |     explicit IScreenShotControlService(Core::System& system_); | ||||||
|     ~CAPS_SC() override; |     ~IScreenShotControlService() override; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -5,7 +5,8 @@ | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { | IScreenShotService::IScreenShotService(Core::System& system_) | ||||||
|  |     : ServiceFramework{system_, "caps:ss"} { | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {201, nullptr, "SaveScreenShot"}, |         {201, nullptr, "SaveScreenShot"}, | ||||||
| @@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { | |||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
|  |  | ||||||
| CAPS_SS::~CAPS_SS() = default; | IScreenShotService::~IScreenShotService() = default; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ class System; | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class CAPS_SS final : public ServiceFramework<CAPS_SS> { | class IScreenShotService final : public ServiceFramework<IScreenShotService> { | ||||||
| public: | public: | ||||||
|     explicit CAPS_SS(Core::System& system_); |     explicit IScreenShotService(Core::System& system_); | ||||||
|     ~CAPS_SS() override; |     ~IScreenShotService() override; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -7,10 +7,11 @@ | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { | IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) | ||||||
|  |     : ServiceFramework{system_, "caps:su"} { | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, |         {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||||
|         {201, nullptr, "SaveScreenShot"}, |         {201, nullptr, "SaveScreenShot"}, | ||||||
|         {203, nullptr, "SaveScreenShotEx0"}, |         {203, nullptr, "SaveScreenShotEx0"}, | ||||||
|         {205, nullptr, "SaveScreenShotEx1"}, |         {205, nullptr, "SaveScreenShotEx1"}, | ||||||
| @@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { | |||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
|  |  | ||||||
| CAPS_SU::~CAPS_SU() = default; | IScreenShotApplicationService::~IScreenShotApplicationService() = default; | ||||||
|  |  | ||||||
| void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) { | void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto library_version{rp.Pop<u64>()}; |     const auto library_version{rp.Pop<u64>()}; | ||||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; |     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||||
|   | |||||||
| @@ -11,10 +11,10 @@ class System; | |||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class CAPS_SU final : public ServiceFramework<CAPS_SU> { | class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { | ||||||
| public: | public: | ||||||
|     explicit CAPS_SU(Core::System& system_); |     explicit IScreenShotApplicationService(Core::System& system_); | ||||||
|     ~CAPS_SU() override; |     ~IScreenShotApplicationService() override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); |     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||||
|   | |||||||
							
								
								
									
										184
									
								
								src/core/hle/service/caps/caps_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/core/hle/service/caps/caps_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
|  | namespace Service::Capture { | ||||||
|  |  | ||||||
|  | // This is nn::album::ImageOrientation | ||||||
|  | enum class AlbumImageOrientation { | ||||||
|  |     None, | ||||||
|  |     Rotate90, | ||||||
|  |     Rotate180, | ||||||
|  |     Rotate270, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // This is nn::album::AlbumReportOption | ||||||
|  | enum class AlbumReportOption : s32 { | ||||||
|  |     Disable, | ||||||
|  |     Enable, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum class ContentType : u8 { | ||||||
|  |     Screenshot = 0, | ||||||
|  |     Movie = 1, | ||||||
|  |     ExtraMovie = 3, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum class AlbumStorage : u8 { | ||||||
|  |     Nand, | ||||||
|  |     Sd, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum class ScreenShotDecoderFlag : u64 { | ||||||
|  |     None = 0, | ||||||
|  |     EnableFancyUpsampling = 1 << 0, | ||||||
|  |     EnableBlockSmoothing = 1 << 1, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // This is nn::capsrv::AlbumFileDateTime | ||||||
|  | struct AlbumFileDateTime { | ||||||
|  |     u16 year{}; | ||||||
|  |     u8 month{}; | ||||||
|  |     u8 day{}; | ||||||
|  |     u8 hour{}; | ||||||
|  |     u8 minute{}; | ||||||
|  |     u8 second{}; | ||||||
|  |     u8 unique_id{}; | ||||||
|  |  | ||||||
|  |     friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default; | ||||||
|  |     friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { | ||||||
|  |         if (a.year > b.year) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.month > b.month) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.day > b.day) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.hour > b.hour) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.minute > b.minute) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return a.second > b.second; | ||||||
|  |     }; | ||||||
|  |     friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) { | ||||||
|  |         if (a.year < b.year) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.month < b.month) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.day < b.day) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.hour < b.hour) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (a.minute < b.minute) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return a.second < b.second; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size."); | ||||||
|  |  | ||||||
|  | // This is nn::album::AlbumEntry | ||||||
|  | struct AlbumFileEntry { | ||||||
|  |     u64 size{}; // Size of the entry | ||||||
|  |     u64 hash{}; // AES256 with hardcoded key over AlbumEntry | ||||||
|  |     AlbumFileDateTime datetime{}; | ||||||
|  |     AlbumStorage storage{}; | ||||||
|  |     ContentType content{}; | ||||||
|  |     INSERT_PADDING_BYTES(5); | ||||||
|  |     u8 unknown{}; // Set to 1 on official SW | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size."); | ||||||
|  |  | ||||||
|  | struct AlbumFileId { | ||||||
|  |     u64 application_id{}; | ||||||
|  |     AlbumFileDateTime date{}; | ||||||
|  |     AlbumStorage storage{}; | ||||||
|  |     ContentType type{}; | ||||||
|  |     INSERT_PADDING_BYTES(0x5); | ||||||
|  |     u8 unknown{}; | ||||||
|  |  | ||||||
|  |     friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size"); | ||||||
|  |  | ||||||
|  | // This is nn::capsrv::AlbumEntry | ||||||
|  | struct AlbumEntry { | ||||||
|  |     u64 entry_size{}; | ||||||
|  |     AlbumFileId file_id{}; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size."); | ||||||
|  |  | ||||||
|  | // This is nn::capsrv::ApplicationAlbumEntry | ||||||
|  | struct ApplicationAlbumEntry { | ||||||
|  |     u64 size{}; // Size of the entry | ||||||
|  |     u64 hash{}; // AES256 with hardcoded key over AlbumEntry | ||||||
|  |     AlbumFileDateTime datetime{}; | ||||||
|  |     AlbumStorage storage{}; | ||||||
|  |     ContentType content{}; | ||||||
|  |     INSERT_PADDING_BYTES(5); | ||||||
|  |     u8 unknown{1}; // Set to 1 on official SW | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size."); | ||||||
|  |  | ||||||
|  | // This is nn::capsrv::ApplicationAlbumFileEntry | ||||||
|  | struct ApplicationAlbumFileEntry { | ||||||
|  |     ApplicationAlbumEntry entry{}; | ||||||
|  |     AlbumFileDateTime datetime{}; | ||||||
|  |     u64 unknown{}; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, | ||||||
|  |               "ApplicationAlbumFileEntry has incorrect size."); | ||||||
|  |  | ||||||
|  | struct ApplicationData { | ||||||
|  |     std::array<u8, 0x400> data{}; | ||||||
|  |     u32 data_size{}; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size"); | ||||||
|  |  | ||||||
|  | struct ScreenShotAttribute { | ||||||
|  |     u32 unknown_0{}; | ||||||
|  |     AlbumImageOrientation orientation{}; | ||||||
|  |     u32 unknown_1{}; | ||||||
|  |     u32 unknown_2{}; | ||||||
|  |     INSERT_PADDING_BYTES(0x30); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size"); | ||||||
|  |  | ||||||
|  | struct ScreenShotDecodeOption { | ||||||
|  |     ScreenShotDecoderFlag flags{}; | ||||||
|  |     INSERT_PADDING_BYTES(0x18); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size"); | ||||||
|  |  | ||||||
|  | struct LoadAlbumScreenShotImageOutput { | ||||||
|  |     s64 width{}; | ||||||
|  |     s64 height{}; | ||||||
|  |     ScreenShotAttribute attribute{}; | ||||||
|  |     INSERT_PADDING_BYTES(0x400); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450, | ||||||
|  |               "LoadAlbumScreenShotImageOutput is an invalid size"); | ||||||
|  |  | ||||||
|  | struct LoadAlbumScreenShotImageOutputForApplication { | ||||||
|  |     s64 width{}; | ||||||
|  |     s64 height{}; | ||||||
|  |     ScreenShotAttribute attribute{}; | ||||||
|  |     ApplicationData data{}; | ||||||
|  |     INSERT_PADDING_BYTES(0xAC); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500, | ||||||
|  |               "LoadAlbumScreenShotImageOutput is an invalid size"); | ||||||
|  |  | ||||||
|  | } // namespace Service::Capture | ||||||
| @@ -2,45 +2,29 @@ | |||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/hle/service/caps/caps.h" | #include "core/hle/service/caps/caps_manager.h" | ||||||
|  | #include "core/hle/service/caps/caps_types.h" | ||||||
| #include "core/hle/service/caps/caps_u.h" | #include "core/hle/service/caps/caps_u.h" | ||||||
| #include "core/hle/service/ipc_helpers.h" | #include "core/hle/service/ipc_helpers.h" | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  |  | ||||||
| class IAlbumAccessorApplicationSession final | IAlbumApplicationService::IAlbumApplicationService(Core::System& system_, | ||||||
|     : public ServiceFramework<IAlbumAccessorApplicationSession> { |                                                    std::shared_ptr<AlbumManager> album_manager) | ||||||
| public: |     : ServiceFramework{system_, "caps:u"}, manager{album_manager} { | ||||||
|     explicit IAlbumAccessorApplicationSession(Core::System& system_) |  | ||||||
|         : ServiceFramework{system_, "IAlbumAccessorApplicationSession"} { |  | ||||||
|         // clang-format off |  | ||||||
|         static const FunctionInfo functions[] = { |  | ||||||
|             {2001, nullptr, "OpenAlbumMovieReadStream"}, |  | ||||||
|             {2002, nullptr, "CloseAlbumMovieReadStream"}, |  | ||||||
|             {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, |  | ||||||
|             {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, |  | ||||||
|             {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, |  | ||||||
|         }; |  | ||||||
|         // clang-format on |  | ||||||
|  |  | ||||||
|         RegisterHandlers(functions); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} { |  | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"}, |         {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||||
|         {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, |         {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"}, | ||||||
|         {103, nullptr, "DeleteAlbumContentsFileForApplication"}, |         {103, nullptr, "DeleteAlbumFileByAruid"}, | ||||||
|         {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, |         {104, nullptr, "GetAlbumFileSizeByAruid"}, | ||||||
|         {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, |         {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, | ||||||
|         {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, |         {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, | ||||||
|         {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, |         {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, | ||||||
|         {130, nullptr, "PrecheckToCreateContentsForApplication"}, |         {130, nullptr, "PrecheckToCreateContentsByAruid"}, | ||||||
|         {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, |         {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, | ||||||
|         {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, |         {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, | ||||||
|         {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, |         {142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, | ||||||
|         {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, |         {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, | ||||||
|         {144, nullptr, "GetAllAlbumFileList3AaeAruid"}, |         {144, nullptr, "GetAllAlbumFileList3AaeAruid"}, | ||||||
|         {60002, nullptr, "OpenAccessorSessionForApplication"}, |         {60002, nullptr, "OpenAccessorSessionForApplication"}, | ||||||
| @@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} { | |||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| } | } | ||||||
|  |  | ||||||
| CAPS_U::~CAPS_U() = default; | IAlbumApplicationService::~IAlbumApplicationService() = default; | ||||||
|  |  | ||||||
| void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) { | void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto library_version{rp.Pop<u64>()}; |     const auto library_version{rp.Pop<u64>()}; | ||||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; |     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||||
| @@ -64,10 +48,7 @@ void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) { | |||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
| void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) { | void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) { | ||||||
|     // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an |  | ||||||
|     // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total |  | ||||||
|     // output entries (which is copied to a s32 by official SW). |  | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto pid{rp.Pop<s32>()}; |     const auto pid{rp.Pop<s32>()}; | ||||||
|     const auto content_type{rp.PopEnum<ContentType>()}; |     const auto content_type{rp.PopEnum<ContentType>()}; | ||||||
| @@ -75,26 +56,49 @@ void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) { | |||||||
|     const auto end_posix_time{rp.Pop<s64>()}; |     const auto end_posix_time{rp.Pop<s64>()}; | ||||||
|     const auto applet_resource_user_id{rp.Pop<u64>()}; |     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||||
|  |  | ||||||
|     // TODO: Update this when we implement the album. |     LOG_WARNING(Service_Capture, | ||||||
|     // Currently we do not have a method of accessing album entries, set this to 0 for now. |                 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " | ||||||
|     constexpr u32 total_entries_1{}; |                 "end_posix_time={}, applet_resource_user_id={}", | ||||||
|     constexpr u32 total_entries_2{}; |                 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id); | ||||||
|  |  | ||||||
|     LOG_WARNING( |     // TODO: Translate posix to DateTime | ||||||
|         Service_Capture, |  | ||||||
|         "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " |     std::vector<ApplicationAlbumFileEntry> entries; | ||||||
|         "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}", |     const Result result = | ||||||
|         pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, |         manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id); | ||||||
|         total_entries_1, total_entries_2); |  | ||||||
|  |     if (!entries.empty()) { | ||||||
|  |         ctx.WriteBuffer(entries); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(result); | ||||||
|     rb.Push(total_entries_1); |     rb.Push<u64>(entries.size()); | ||||||
|     rb.Push(total_entries_2); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { | void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { | ||||||
|     GetAlbumContentsFileListForApplication(ctx); |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto pid{rp.Pop<s32>()}; | ||||||
|  |     const auto content_type{rp.PopEnum<ContentType>()}; | ||||||
|  |     const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()}; | ||||||
|  |     const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()}; | ||||||
|  |     const auto applet_resource_user_id{rp.Pop<u64>()}; | ||||||
|  |  | ||||||
|  |     LOG_WARNING(Service_Capture, | ||||||
|  |                 "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid, | ||||||
|  |                 content_type, applet_resource_user_id); | ||||||
|  |  | ||||||
|  |     std::vector<ApplicationAlbumFileEntry> entries; | ||||||
|  |     const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time, | ||||||
|  |                                                     end_date_time, applet_resource_user_id); | ||||||
|  |  | ||||||
|  |     if (!entries.empty()) { | ||||||
|  |         ctx.WriteBuffer(entries); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|  |     rb.Push(result); | ||||||
|  |     rb.Push<u64>(entries.size()); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
| @@ -10,16 +10,20 @@ class System; | |||||||
| } | } | ||||||
|  |  | ||||||
| namespace Service::Capture { | namespace Service::Capture { | ||||||
|  | class AlbumManager; | ||||||
|  |  | ||||||
| class CAPS_U final : public ServiceFramework<CAPS_U> { | class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> { | ||||||
| public: | public: | ||||||
|     explicit CAPS_U(Core::System& system_); |     explicit IAlbumApplicationService(Core::System& system_, | ||||||
|     ~CAPS_U() override; |                                       std::shared_ptr<AlbumManager> album_manager); | ||||||
|  |     ~IAlbumApplicationService() override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); |     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||||
|     void GetAlbumContentsFileListForApplication(HLERequestContext& ctx); |     void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx); | ||||||
|     void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); |     void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); | ||||||
|  |  | ||||||
|  |     std::shared_ptr<AlbumManager> manager = nullptr; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Capture | } // namespace Service::Capture | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Narr the Reg
					Narr the Reg