From eb078b295503f68c755a921b9d30b73b6a4997ab Mon Sep 17 00:00:00 2001 From: HookedBehemoth Date: Fri, 24 Jan 2020 07:17:50 +0100 Subject: [PATCH] add caps:c --- nx/include/switch.h | 1 + nx/include/switch/services/caps.h | 5 + nx/include/switch/services/capsc.h | 51 +++++ nx/source/services/capsc.c | 314 +++++++++++++++++++++++++++++ 4 files changed, 371 insertions(+) create mode 100644 nx/include/switch/services/capsc.h create mode 100644 nx/source/services/capsc.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 81f14dcf..465d4262 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -93,6 +93,7 @@ extern "C" { #include "switch/services/psc.h" #include "switch/services/caps.h" #include "switch/services/capsa.h" +#include "switch/services/capsc.h" #include "switch/services/capsu.h" #include "switch/services/capssc.h" #include "switch/services/capssu.h" diff --git a/nx/include/switch/services/caps.h b/nx/include/switch/services/caps.h index 0aa966f1..f12c9d93 100644 --- a/nx/include/switch/services/caps.h +++ b/nx/include/switch/services/caps.h @@ -201,6 +201,11 @@ typedef struct { u8 unk_x8[8]; ///< Unknown } CapsAlbumCache; +/// AlbumCommitOutput +typedef struct { + u64 unk[4]; ///< Unknown. Official sw sets this to 0. +} CapsAlbumCommitOutput; + /// Gets the ShimLibraryVersion. u64 capsGetShimLibraryVersion(void); diff --git a/nx/include/switch/services/capsc.h b/nx/include/switch/services/capsc.h new file mode 100644 index 00000000..bcc1753f --- /dev/null +++ b/nx/include/switch/services/capsc.h @@ -0,0 +1,51 @@ +/** + * @file capsc.h + * @brief Album Control (caps:c) service IPC wrapper. + * @author Behemoth + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../sf/service.h" +#include "../services/caps.h" + +/// Initialize caps:c +Result capscInitialize(void); + +/// Exit caps:c. +void capscExit(void); + +/// Gets the Service for caps:c. +Service* capscGetServiceSession(void); +Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage); +Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage); +Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid); +Result capscCheckApplicationIdRegistered(u64 application_id); +Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id); +Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size); +Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size); + +Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id); +Result capscCloseAlbumMovieStream(u64 stream); +Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size); +Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); +Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream); +Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size); +Result capscReadImageDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size); +Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute); +Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id); +Result capscFinishAlbumMovieWriteStream(u64 stream); +Result capscCommitAlbumMovieWriteStream(u64 stream); +Result capscDiscardAlbumMovieWriteStream(u64 stream); +Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream); +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out); +Result capscStartAlbumMovieWriteStreamDataSection(u64 stream); +Result capscEndAlbumMovieWriteStreamDataSection(u64 stream); +Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream); +Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream); +Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size); +Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size); +Result capscWriteMetaToAlbumMovieWriteStream(); +Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream); +Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size); +Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size); diff --git a/nx/source/services/capsc.c b/nx/source/services/capsc.c new file mode 100644 index 00000000..f9def1b8 --- /dev/null +++ b/nx/source/services/capsc.c @@ -0,0 +1,314 @@ +#define NX_SERVICE_ASSUME_NON_DOMAIN +#include +#include +#include "service_guard.h" +#include "runtime/hosversion.h" +#include "services/applet.h" +#include "services/capsc.h" + +static Service g_capscSrv; +static Service g_capscControl; + +NX_GENERATE_SERVICE_GUARD(capsc); + +Result _capscInitialize(void) { + return smGetService(&g_capscSrv, "caps:c"); +} + +void _capscCleanup(void) { + serviceClose(&g_capscControl); + serviceClose(&g_capscSrv); +} + +Service* capscGetServiceSession(void) { + return &g_capscSrv; +} + +static Result _capscCmdInU8NoOut(Service *srv, u32 cmd_id, u8 inval) { + return serviceDispatchIn(srv, cmd_id, inval); +} + +Result capscNotifyAlbumStorageIsAvailable(CapsAlbumStorage storage) { + u8 inval = storage; + return _capscCmdInU8NoOut(&g_capscSrv, 1001, inval); +} + +Result capscNotifyAlbumStorageIsUnAvailable(CapsAlbumStorage storage) { + u8 inval = storage; + return _capscCmdInU8NoOut(&g_capscSrv, 1002, inval); +} + +Result capscGetApplicationIdFromAruid(u64 *application_id, u64 aruid) { + return serviceDispatchInOut(&g_capscSrv, 2013, aruid, *application_id); +} + +Result capscCheckApplicationIdRegistered(u64 application_id) { + return _capscCmdInU8NoOut(&g_capscSrv, 2014, application_id); +} + +Result capscGenerateCurrentAlbumFileId(u64 application_id, CapsAlbumFileContents contents, CapsAlbumFileId *file_id) { + const struct { + u8 type; + u64 application_id; + } in = { contents, application_id }; + return serviceDispatchInOut(&g_capscSrv, 2101, in, *file_id); +} + +Result capscSaveAlbumScreenShotFile(CapsAlbumFileId *file_id, void* buffer, u64 buffer_size) { + if (hosversionAtLeast(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return serviceDispatchIn(&g_capscSrv, 2201, file_id, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, buffer_size }, }, + ); +} + +Result capscSaveAlbumScreenShotFileEx(CapsAlbumFileId *file_id, u64 unk_0, u64 unk_1, u64 unk_2, void* buffer, u64 buffer_size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + CapsAlbumFileId file_id; + u64 unk_0; + u64 unk_1; + u64 unk_2; + } in = { *file_id, unk_0, unk_1, unk_2 }; + return serviceDispatchIn(&g_capscSrv, 2202, in, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, buffer_size }, }, + ); +} + +Result _capscSetOverlayThumbnailData(u32 cmd_id, CapsAlbumFileId *file_id, void* buffer, u64 size) { + return serviceDispatchIn(&g_capscSrv, cmd_id, *file_id, + .buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size }, }, + ); +} + +Result capscSetOverlayScreenShotThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _capscSetOverlayThumbnailData(2301, file_id, buffer, size); +} + +Result capscSetOverlayMovieThumbnailData(CapsAlbumFileId *file_id, void* buffer, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _capscSetOverlayThumbnailData(2302, file_id, buffer, size); +} + +static Result _capscOpenControlSession(Service *srv_out) { + u64 AppletResourceUserId = appletGetAppletResourceUserId(); + + return serviceDispatchIn(&g_capscSrv, 60001, AppletResourceUserId, + .in_send_pid = true, + .out_num_objects = 1, + .out_objects = srv_out, + ); +} + +Result _capscOpenAlbumMovieStream(u32 cmd_id, const CapsAlbumFileId *file_id, u64 *stream) { + return serviceDispatchInOut(&g_capscControl, cmd_id, *file_id, *stream); +} + +Result _capscControlReadDataFromAlbumMovieStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 offset; + } in = { stream, offset }; + + return serviceDispatchInOut(&g_capscControl, cmd_id, in, *actual_size, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { buffer, size } }, + ); +} + +Result _capscControlCmdInU8NoOut(u32 cmd_id, u8 inval) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchIn(&g_capscControl, cmd_id, inval); +} + +Result capscOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + + if (!serviceIsActive(&g_capscControl)) rc = _capscOpenControlSession(&g_capscControl); + + if (R_SUCCEEDED(rc)) rc = _capscOpenAlbumMovieStream(2001, file_id, stream); + + return rc; +} + +Result capscCloseAlbumMovieStream(u64 stream) { + return _capscControlCmdInU8NoOut(2002, stream); +} + +Result capscGetAlbumMovieStreamSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2003, stream, *size); +} + +Result capscReadMovieDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2004, stream, offset, buffer, size, actual_size); +} + +Result capscGetAlbumMovieReadStreamBrokenReason(u64 stream) { + return _capscControlCmdInU8NoOut(2005, stream); +} + +Result capscGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2006, stream, *size); +} + +Result capscReadImageDataFromAlbumMovieReadStream(u64 stream, u64 offset, void* buffer, size_t size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2007, stream, offset, buffer, size, actual_size); +} + +Result capscReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2008, stream, *attribute); +} + +Result capscOpenAlbumMovieWriteStream(u64 *stream, const CapsAlbumFileId *file_id) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + + if (!serviceIsActive(&g_capscControl)) rc = _capscOpenControlSession(&g_capscControl); + + if (R_SUCCEEDED(rc)) rc = _capscOpenAlbumMovieStream(2401, file_id, stream); + + return rc; +} + +Result capscFinishAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2402, stream); +} + +Result capscCommitAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2403, stream); +} + +Result capscDiscardAlbumMovieWriteStream(u64 stream) { + return _capscControlCmdInU8NoOut(2404, stream); +} + +Result capscDiscardAlbumMovieWriteStreamNoDelete(u64 stream) { + return _capscControlCmdInU8NoOut(2405, stream); +} + +Result capscCommitAlbumMovieWriteStreamEx(u64 stream, CapsAlbumCommitOutput *out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2008, stream, *out); +} + +Result capscStartAlbumMovieWriteStreamDataSection(u64 stream) { + return _capscControlCmdInU8NoOut(2411, stream); +} + +Result capscEndAlbumMovieWriteStreamDataSection(u64 stream) { + return _capscControlCmdInU8NoOut(2412, stream); +} + +Result capscStartAlbumMovieWriteStreamMetaSection(u64 stream) { + return _capscControlCmdInU8NoOut(2413, stream); +} + +Result capscEndAlbumMovieWriteStreamMetaSection(u64 stream) { + return _capscControlCmdInU8NoOut(2414, stream); +} + +Result capscReadDataFromAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size, u64 *actual_size) { + return _capscControlReadDataFromAlbumMovieStream(2421, stream, offset, buffer, size, actual_size); +} + +Result _capscWriteToAlbumMovieWriteStream(u32 cmd_id, u64 stream, u64 offset, void* buffer, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 offset; + } in = { stream, offset }; + return serviceDispatchIn(&g_capscControl, cmd_id, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size } }, + ); +} + +Result capscWriteDataToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size) { + return _capscWriteToAlbumMovieWriteStream(2422, stream, offset, buffer, size); +} + +Result capscWriteMetaToAlbumMovieWriteStream(u64 stream, u64 offset, void* buffer, u64 size) { + return _capscWriteToAlbumMovieWriteStream(2422, stream, offset, buffer, size); +} + +Result capscGetAlbumMovieWriteStreamBrokenReason(u64 stream) { + return _capscControlCmdInU8NoOut(2431, stream); +} + +Result capscGetAlbumMovieWriteStreamDataSize(u64 stream, u64 *size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return serviceDispatchInOut(&g_capscControl, 2433, stream, *size); +} + +Result capscSetAlbumMovieWriteStreamDataSize(u64 stream, u64 size) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (!serviceIsActive(&g_capscControl)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u64 stream; + u64 size; + } in = { stream, size }; + return serviceDispatchIn(&g_capscControl, 2434, in); +} + + +