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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (result.IsSuccess()) {
 | 
				
			||||||
        ctx.WriteBuffer(image_output, 0);
 | 
					        ctx.WriteBuffer(image_output, 0);
 | 
				
			||||||
        ctx.WriteBuffer(image, 1);
 | 
					        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 (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);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (result.IsSuccess()) {
 | 
				
			||||||
        ctx.WriteBuffer(image_output, 0);
 | 
					        ctx.WriteBuffer(image_output, 0);
 | 
				
			||||||
        ctx.WriteBuffer(image, 1);
 | 
					        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.
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
            // TODO: Implement proper indexing to allow more images
 | 
					 | 
				
			||||||
            if (sd_image_paths.size() > 0xFF) {
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (GetAlbumEntry(entry, full_path).IsSuccess()) {
 | 
					 | 
				
			||||||
                sd_image_paths.push_back(full_path);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        Common::FS::DirEntryFilter::File);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    is_mounted = true;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Result IAlbumAccessorService::GetAlbumEntry(AlbumEntry& out_entry,
 | 
					    if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
 | 
				
			||||||
                                            const std::filesystem::path& path) {
 | 
					        if (in_result.description - 0x514 < 100) {
 | 
				
			||||||
    std::istringstream line_stream(path.filename().string());
 | 
					            return ResultInvalidFileData;
 | 
				
			||||||
    std::string date;
 | 
					        }
 | 
				
			||||||
    std::string application;
 | 
					        if (in_result.description - 0x5dc < 100) {
 | 
				
			||||||
    std::string time;
 | 
					            return ResultInvalidFileData;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // 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;
 | 
					        if (in_result.description - 0x578 < 100) {
 | 
				
			||||||
 | 
					            if (in_result == ResultFileCountLimit) {
 | 
				
			||||||
 | 
					                return ResultUnknown22;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ResultUnknown25;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Result IAlbumAccessorService::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
 | 
					        if (in_result.raw < ResultUnknown1801.raw) {
 | 
				
			||||||
                                        int width, int height, ScreenShotDecoderFlag flag) {
 | 
					            if (in_result == ResultUnknown1202) {
 | 
				
			||||||
    if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) {
 | 
					                return ResultUnknown810;
 | 
				
			||||||
        return ResultUnknown;
 | 
					            }
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1203) {
 | 
				
			||||||
 | 
					                return ResultUnknown810;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1701) {
 | 
				
			||||||
 | 
					                return ResultUnknown5;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (in_result.raw < ResultUnknown1803.raw) {
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1801) {
 | 
				
			||||||
 | 
					                return ResultUnknown5;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1802) {
 | 
				
			||||||
 | 
					                return ResultUnknown6;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1803) {
 | 
				
			||||||
 | 
					                return ResultUnknown7;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (in_result == ResultUnknown1804) {
 | 
				
			||||||
 | 
					                return ResultOutOfRange;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ResultUnknown1024;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read,
 | 
					    if (in_result.module == ErrorModule::FS) {
 | 
				
			||||||
                                     Common::FS::FileType::BinaryFile};
 | 
					        if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) ||
 | 
				
			||||||
 | 
					            (((in_result.description - 3000) >> 3) < 0x271)) {
 | 
				
			||||||
    std::vector<u8> raw_file(db_file.GetSize());
 | 
					            // TODO: Translate FS error
 | 
				
			||||||
    if (db_file.Read(raw_file) != raw_file.size()) {
 | 
					            return in_result;
 | 
				
			||||||
        return ResultUnknown;
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int filter_flag = STBIR_FILTER_DEFAULT;
 | 
					    return in_result;
 | 
				
			||||||
    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
 | 
					    // clang-format off
 | 
				
			||||||
    static const FunctionInfo functions[] = {
 | 
					    static const FunctionInfo functions[] = {
 | 
				
			||||||
            {2001, nullptr, "OpenAlbumMovieReadStream"},
 | 
					        {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
 | 
				
			||||||
            {2002, nullptr, "CloseAlbumMovieReadStream"},
 | 
					        {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
 | 
				
			||||||
            {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
 | 
					        {103, nullptr, "DeleteAlbumFileByAruid"},
 | 
				
			||||||
            {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
 | 
					        {104, nullptr, "GetAlbumFileSizeByAruid"},
 | 
				
			||||||
            {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        // clang-format on
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        RegisterHandlers(functions);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
 | 
					 | 
				
			||||||
    // clang-format off
 | 
					 | 
				
			||||||
    static const FunctionInfo functions[] = {
 | 
					 | 
				
			||||||
        {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
 | 
					 | 
				
			||||||
        {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
 | 
					 | 
				
			||||||
        {103, nullptr, "DeleteAlbumContentsFileForApplication"},
 | 
					 | 
				
			||||||
        {104, nullptr, "GetAlbumContentsFileSizeForApplication"},
 | 
					 | 
				
			||||||
        {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.
 | 
					 | 
				
			||||||
    constexpr u32 total_entries_1{};
 | 
					 | 
				
			||||||
    constexpr u32 total_entries_2{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LOG_WARNING(
 | 
					 | 
				
			||||||
        Service_Capture,
 | 
					 | 
				
			||||||
                "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
 | 
					                "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
 | 
				
			||||||
        "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
 | 
					                "end_posix_time={}, applet_resource_user_id={}",
 | 
				
			||||||
        pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
 | 
					                pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
 | 
				
			||||||
        total_entries_1, total_entries_2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    IPC::ResponseBuilder rb{ctx, 4};
 | 
					    // TODO: Translate posix to DateTime
 | 
				
			||||||
    rb.Push(ResultSuccess);
 | 
					
 | 
				
			||||||
    rb.Push(total_entries_1);
 | 
					    std::vector<ApplicationAlbumFileEntry> entries;
 | 
				
			||||||
    rb.Push(total_entries_2);
 | 
					    const Result result =
 | 
				
			||||||
 | 
					        manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!entries.empty()) {
 | 
				
			||||||
 | 
					        ctx.WriteBuffer(entries);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
 | 
					    IPC::ResponseBuilder rb{ctx, 4};
 | 
				
			||||||
    GetAlbumContentsFileListForApplication(ctx);
 | 
					    rb.Push(result);
 | 
				
			||||||
 | 
					    rb.Push<u64>(entries.size());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& 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