early-access version 3908

This commit is contained in:
pineappleEA
2023-10-02 11:23:24 +02:00
parent 4ca1221654
commit d663a10fcf
47 changed files with 36904 additions and 8885 deletions

View File

@@ -764,6 +764,64 @@ void AppletMessageQueue::OperationModeChanged() {
on_operation_mode_changed->Signal();
}
ILockAccessor::ILockAccessor(Core::System& system_)
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &ILockAccessor::TryLock, "TryLock"},
{2, &ILockAccessor::Unlock, "Unlock"},
{3, &ILockAccessor::GetEvent, "GetEvent"},
{4,&ILockAccessor::IsLocked, "IsLocked"},
};
// clang-format on
RegisterHandlers(functions);
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
}
ILockAccessor::~ILockAccessor() = default;
void ILockAccessor::TryLock(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto return_handle = rp.Pop<bool>();
LOG_INFO(Service_AM, "called, return_handle={}", return_handle);
is_locked = true;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
void ILockAccessor::Unlock(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called");
is_locked = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called");
lock_event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(lock_event->GetReadableEvent());
}
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push<u8>(is_locked);
}
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
std::shared_ptr<AppletMessageQueue> msg_queue_)
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
@@ -787,7 +845,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"},
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
{32, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"},
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
@@ -805,7 +863,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
{68, nullptr, "GetBuiltInDisplayType"},
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
@@ -886,6 +944,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown = rp.Pop<u32>();
LOG_INFO(Service_AM, "called, unknown={}", unknown);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILockAccessor>(system);
}
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called");
@@ -970,6 +1040,14 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
apm_sys->SetCpuBoostMode(ctx);
}
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto system_button{rp.PopEnum<SystemButtonType>()};
@@ -1493,6 +1571,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
case Applets::AppletId::MiiEdit:
PushInShowMiiEditData();
break;
case Applets::AppletId::PhotoViewer:
PushInShowAlbum();
break;
default:
break;
}
@@ -1569,6 +1650,23 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
rb.PushRaw(applet_info);
}
void ILibraryAppletSelfAccessor::PushInShowAlbum() {
const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3,
.size = Applets::CommonArgumentSize::Version3,
.library_version = 1,
.theme_color = Applets::ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> settings_data{2};
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
queue_data.emplace_back(std::move(argument_data));
queue_data.emplace_back(std::move(settings_data));
}
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3,

View File

@@ -195,6 +195,23 @@ private:
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
};
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
public:
explicit ILockAccessor(Core::System& system_);
~ILockAccessor() override;
private:
void TryLock(HLERequestContext& ctx);
void Unlock(HLERequestContext& ctx);
void GetEvent(HLERequestContext& ctx);
void IsLocked(HLERequestContext& ctx);
bool is_locked{};
Kernel::KEvent* lock_event;
KernelHelpers::ServiceContext service_context;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
explicit ICommonStateGetter(Core::System& system_,
@@ -237,6 +254,7 @@ private:
void GetCurrentFocusState(HLERequestContext& ctx);
void RequestToAcquireSleepLock(HLERequestContext& ctx);
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
void GetReaderLockAccessorEx(HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
void GetOperationMode(HLERequestContext& ctx);
void GetPerformanceMode(HLERequestContext& ctx);
@@ -248,6 +266,7 @@ private:
void EndVrModeEx(HLERequestContext& ctx);
void GetDefaultDisplayResolution(HLERequestContext& ctx);
void SetCpuBoostMode(HLERequestContext& ctx);
void GetBuiltInDisplayType(HLERequestContext& ctx);
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
void GetSettingsPlatformRegion(HLERequestContext& ctx);
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
@@ -327,6 +346,7 @@ private:
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void PushInShowAlbum();
void PushInShowCabinetData();
void PushInShowMiiEditData();

View File

@@ -28,8 +28,8 @@ public:
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{22, nullptr, "GetHomeMenuFunctions"},
{23, nullptr, "GetGlobalStateController"},
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
@@ -110,6 +110,22 @@ private:
rb.PushIpcInterface<IAppletCommonFunctions>(system);
}
void GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
void GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IGlobalStateController>(system);
}
void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");

View File

@@ -138,6 +138,10 @@ void Error::Initialize() {
CopyArgumentData(data, args->application_error);
error_code = Result(args->application_error.error_code);
break;
case ErrorAppletMode::ShowErrorPctl:
CopyArgumentData(data, args->error_record);
error_code = Decode64BitError(args->error_record.error_code_64);
break;
case ErrorAppletMode::ShowErrorRecord:
CopyArgumentData(data, args->error_record);
error_code = Decode64BitError(args->error_record.error_code_64);
@@ -191,6 +195,7 @@ void Error::Execute() {
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
break;
}
case ErrorAppletMode::ShowErrorPctl:
case ErrorAppletMode::ShowErrorRecord:
reporter.SaveErrorReport(title_id, error_code,
fmt::format("{:016X}", args->error_record.posix_time));

View File

@@ -16,7 +16,7 @@ namespace Service::Capture {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(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));

View File

@@ -1,7 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2020 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 "core/hle/service/caps/caps_a.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
@@ -26,15 +33,16 @@ public:
}
};
CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
IAlbumAccessorService::IAlbumAccessorService(Core::System& system_)
: ServiceFramework{system_, "caps:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAlbumFileCount"},
{1, nullptr, "GetAlbumFileList"},
{2, nullptr, "LoadAlbumFile"},
{3, nullptr, "DeleteAlbumFile"},
{3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
{4, nullptr, "StorageCopyAlbumFile"},
{5, nullptr, "IsAlbumMounted"},
{5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
{6, nullptr, "GetAlbumUsage"},
{7, nullptr, "GetAlbumFileSize"},
{8, nullptr, "LoadAlbumFileThumbnail"},
@@ -47,18 +55,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
{15, nullptr, "GetAlbumUsage3"},
{16, nullptr, "GetAlbumMountResult"},
{17, nullptr, "GetAlbumUsage16"},
{18, nullptr, "Unknown18"},
{18, &IAlbumAccessorService::Unknown18, "Unknown18"},
{19, nullptr, "Unknown19"},
{100, nullptr, "GetAlbumFileCountEx0"},
{101, nullptr, "GetAlbumFileListEx0"},
{101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
{202, nullptr, "SaveEditedScreenShot"},
{301, nullptr, "GetLastThumbnail"},
{302, nullptr, "GetLastOverlayMovieThumbnail"},
{401, nullptr, "GetAutoSavingStorage"},
{401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
{1002, nullptr, "LoadAlbumScreenShotImageEx1"},
{1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"},
{1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
{1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
{8001, nullptr, "ForceAlbumUnmounted"},
{8002, nullptr, "ResetAlbumMountStatus"},
{8011, nullptr, "RefreshAlbumCache"},
@@ -74,6 +82,294 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
RegisterHandlers(functions);
}
CAPS_A::~CAPS_A() = default;
IAlbumAccessorService::~IAlbumAccessorService() = default;
void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
file_id.application_id, file_id.storage, file_id.type);
if (file_id.storage == AlbumStorage::Sd) {
if (!Common::FS::RemoveFile(sd_image_paths[file_id.date.unique_id])) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
LOG_INFO(Service_Capture, "called, storage={}, is_mounted={}", storage, is_mounted);
if (storage == AlbumStorage::Sd) {
FindScreenshots();
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_mounted);
}
void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
struct UnknownBuffer {
INSERT_PADDING_BYTES(0x10);
};
static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
LOG_WARNING(Service_Capture, "(STUBBED) called");
std::vector<UnknownBuffer> buffer{};
if (!buffer.empty()) {
ctx.WriteBuffer(buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(buffer.size()));
}
void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
const auto flags{rp.Pop<u8>()};
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
std::vector<AlbumEntry> entries{};
if (storage == AlbumStorage::Sd) {
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()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(entries.size());
}
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
bool is_autosaving{};
LOG_WARNING(Service_Capture, "(STUBBED) called, is_autosaving={}", is_autosaving);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_autosaving);
}
void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
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);
const LoadAlbumScreenShotImageOutput image_output{
.width = 1280,
.height = 720,
.attribute =
{
.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);
}
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
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);
const LoadAlbumScreenShotImageOutput image_output{
.width = 320,
.height = 180,
.attribute =
{
.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);
}
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IAlbumAccessorService::FindScreenshots() {
is_mounted = false;
sd_image_paths.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;
// 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,
const std::filesystem::path& path) {
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 line_stream2(date);
std::istringstream line_stream3(time);
std::string year;
std::string month;
std::string day;
std::string hour;
std::string minute;
std::string second;
std::getline(line_stream2, year, '-');
std::getline(line_stream2, month, '-');
std::getline(line_stream2, day, '-');
std::getline(line_stream3, hour, '-');
std::getline(line_stream3, minute, '-');
std::getline(line_stream3, 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 IAlbumAccessorService::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
int width, int height, ScreenShotDecoderFlag flag) {
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

View File

@@ -3,6 +3,7 @@
#pragma once
#include "common/fs/fs.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -11,10 +12,120 @@ class System;
namespace Service::Capture {
class CAPS_A final : public ServiceFramework<CAPS_A> {
class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> {
public:
explicit CAPS_A(Core::System& system_);
~CAPS_A() override;
explicit IAlbumAccessorService(Core::System& system_);
~IAlbumAccessorService() override;
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,
Rotat180,
Rotate270,
};
struct ScreenShotAttribute {
u32 unknown_0;
ScreenShotOrientation orientation;
u32 unknown_1;
u32 unknown_2;
INSERT_PADDING_BYTES(0x30);
};
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 IsAlbumMounted(HLERequestContext& ctx);
void Unknown18(HLERequestContext& ctx);
void GetAlbumFileListEx0(HLERequestContext& ctx);
void GetAutoSavingStorage(HLERequestContext& ctx);
void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
private:
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::vector<std::filesystem::path> sd_image_paths{};
};
} // namespace Service::Capture

View File

@@ -545,6 +545,14 @@ void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
}
}
void IGeneralService::IsAnyForegroundRequestAccepted(HLERequestContext& ctx) {
LOG_ERROR(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(0);
}
IGeneralService::IGeneralService(Core::System& system_)
: ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
// clang-format off
@@ -569,7 +577,7 @@ IGeneralService::IGeneralService(Core::System& system_)
{19, nullptr, "SetEthernetCommunicationEnabled"},
{20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
{21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
{22, nullptr, "IsAnyForegroundRequestAccepted"},
{22, &IGeneralService::IsAnyForegroundRequestAccepted, "IsAnyForegroundRequestAccepted"},
{23, nullptr, "PutToSleep"},
{24, nullptr, "WakeUp"},
{25, nullptr, "GetSsidListVersion"},

View File

@@ -35,6 +35,7 @@ private:
void GetInternetConnectionStatus(HLERequestContext& ctx);
void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
void IsAnyForegroundRequestAccepted(HLERequestContext& ctx);
Network::RoomNetwork& network;
};

View File

@@ -7,6 +7,7 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/errors.h"
@@ -502,8 +503,8 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"},
{48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
@@ -516,6 +517,28 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
IContentManagementInterface::~IContentManagementInterface() = default;
void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage));
}
void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage));
}
IDocumentInterface::IDocumentInterface(Core::System& system_)
: ServiceFramework{system_, "IDocumentInterface"} {
// clang-format off

View File

@@ -48,6 +48,10 @@ class IContentManagementInterface final : public ServiceFramework<IContentManage
public:
explicit IContentManagementInterface(Core::System& system_);
~IContentManagementInterface() override;
private:
void GetTotalSpaceSize(HLERequestContext& ctx);
void GetFreeSpaceSize(HLERequestContext& ctx);
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {

View File

@@ -33,7 +33,7 @@ public:
{1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
{1002, nullptr, "ConfirmLaunchApplicationPermission"},
{1003, nullptr, "ConfirmResumeApplicationPermission"},
{1004, nullptr, "ConfirmSnsPostPermission"},
{1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
{1005, nullptr, "ConfirmSystemSettingsPermission"},
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
@@ -236,6 +236,13 @@ private:
states.free_communication = true;
}
void ConfirmSnsPostPermission(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Error::ResultNoFreeCommunication);
}
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
const bool is_temporary_unlocked = false;

View File

@@ -1556,6 +1556,7 @@ void GMainWindow::ConnectMenuEvents() {
// Tools
connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
ReinitializeKeyBehavior::Warning));
connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
connect_menu(ui->action_Load_Cabinet_Eraser,
@@ -1593,6 +1594,7 @@ void GMainWindow::UpdateMenuState() {
};
const std::array applet_actions{
ui->action_Load_Album,
ui->action_Load_Cabinet_Nickname_Owner,
ui->action_Load_Cabinet_Eraser,
ui->action_Load_Cabinet_Restorer,
@@ -4178,19 +4180,42 @@ void GMainWindow::OnToggleStatusBar() {
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
}
void GMainWindow::OnAlbum() {
constexpr u64 AlbumId = 0x010000000000100Dull;
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install the firmware to use the Album applet."));
return;
}
auto album_nca = bis_system->GetEntry(AlbumId, FileSys::ContentRecordType::Program);
if (!album_nca) {
QMessageBox::warning(this, tr("Album Applet"),
tr("Album applet is not available. Please reinstall firmware."));
return;
}
system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer);
const auto filename = QString::fromStdString(album_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path();
BootGame(filename);
}
void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
constexpr u64 CabinetId = 0x0100000000001002ull;
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install the firmware to use the Amiibo applet."));
tr("Please install the firmware to use the Cabinet applet."));
return;
}
auto cabinet_nca = bis_system->GetEntry(CabinetId, FileSys::ContentRecordType::Program);
if (!cabinet_nca) {
QMessageBox::warning(this, tr("Cabinet Applet"),
tr("Amiibo applet is not available. Please reinstall firmware."));
tr("Cabinet applet is not available. Please reinstall firmware."));
return;
}

View File

@@ -374,6 +374,7 @@ private slots:
void ResetWindowSize720();
void ResetWindowSize900();
void ResetWindowSize1080();
void OnAlbum();
void OnCabinet(Service::NFP::CabinetMode mode);
void OnMiiEdit();
void OnCaptureScreenshot();

View File

@@ -160,6 +160,7 @@
<addaction name="action_Verify_installed_contents"/>
<addaction name="separator"/>
<addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/>
<addaction name="action_Load_Mii_Edit"/>
<addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/>
@@ -380,6 +381,11 @@
<string>&amp;Capture Screenshot</string>
</property>
</action>
<action name="action_Load_Album">
<property name="text">
<string>Open &amp;Album</string>
</property>
</action>
<action name="action_Load_Cabinet_Nickname_Owner">
<property name="text">
<string>&amp;Set Nickname and Owner</string>