Added support for capsu. Updated caps.h. Improved docs. Added enum CapsContentType. Added structs CapsScreenShotAttributeForApplication, CapsScreenShotDecodeOption, CapsApplicationAlbumFileEntry, and CapsLoadAlbumScreenShotImageOutputForApplication. Added capsGetDefaultStartDateTime, capsGetDefaultEndDateTime, capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry, and capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry.

This commit is contained in:
yellows8 2019-09-08 19:20:05 -04:00
parent 7d71d4f3a1
commit b7311b6ab1
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
6 changed files with 1028 additions and 7 deletions

View File

@ -85,6 +85,7 @@ extern "C" {
#include "switch/services/ncm.h"
#include "switch/services/psc.h"
#include "switch/services/caps.h"
#include "switch/services/capsu.h"
#include "switch/services/capssc.h"
#include "switch/services/capssu.h"
#include "switch/services/nfc.h"

View File

@ -25,6 +25,13 @@ typedef enum {
AlbumReportOption_Unknown3 = 3, ///< Unknown.
} AlbumReportOption;
/// ContentType
typedef enum {
CapsContentType_Screenshot = 0, ///< Album screenshots.
CapsContentType_Movie = 1, ///< Album videos.
CapsContentType_ExtraMovie = 3, ///< Videos recorded by the current Application host title via \ref grcCreateMovieMaker.
} CapsContentType;
/// ScreenShotAttribute
typedef struct {
u32 unk_x0; ///< Always set to 0 by official sw.
@ -34,11 +41,36 @@ typedef struct {
u8 unk_x10[0x30]; ///< Always set to 0 by official sw.
} CapsScreenShotAttribute;
/// ScreenShotAttributeForApplication. Only unk_x0 is used by official sw.
typedef struct {
u32 unk_x0; ///< Unknown.
u8 unk_x4; ///< Unknown.
u8 unk_x5; ///< Unknown.
u8 unk_x6; ///< Unknown.
u8 pad; ///< Unknown.
u32 unk_x8; ///< Unknown.
u32 unk_xc; ///< Unknown.
u32 unk_x10; ///< Unknown.
u32 unk_x14; ///< Unknown.
u32 unk_x18; ///< Unknown.
u32 unk_x1c; ///< Unknown.
u16 unk_x20; ///< Unknown.
u16 unk_x22; ///< Unknown.
u16 unk_x24; ///< Unknown.
u16 unk_x26; ///< Unknown.
u8 reserved[0x18]; ///< Always zero.
} CapsScreenShotAttributeForApplication;
/// ScreenShotDecodeOption
typedef struct {
u8 unk_x0[0x20]; ///< Unknown. Set to all-zero by official sw.
} CapsScreenShotDecodeOption;
/// AlbumFileDateTime. This corresponds to each field in the Album entry filename, prior to the "-": "YYYYMMDDHHMMSSII".
typedef struct {
u16 year; ///< Year.
u8 month; ///< Month.
u8 day; ///< Day.
u8 day; ///< Day of the month.
u8 hour; ///< Hour.
u8 minute; ///< Minute.
u8 second; ///< Second.
@ -56,15 +88,35 @@ typedef struct {
/// AlbumEntry
typedef struct {
u8 unk_x0[0x8];
CapsAlbumEntryId id;
u8 unk_x0[0x8]; ///< Unknown.
CapsAlbumEntryId id; ///< \ref CapsAlbumEntryId
} CapsAlbumEntry;
/// ApplicationAlbumEntry
typedef struct {
u8 data[0x20];
union {
u8 data[0x20]; ///< Data.
struct {
u8 unk_x0[0x20]; ///< Unknown.
} v0; ///< Pre-7.0.0
struct {
u8 unk_x0[0x8]; ///< Unknown.
u8 unk_x8[0x8]; ///< Unknown.
CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
u8 unk_x18[0x8]; ///< Unknown.
} v1; ///< [7.0.0+]
};
} CapsApplicationAlbumEntry;
/// ApplicationAlbumFileEntry
typedef struct {
CapsApplicationAlbumEntry entry; ///< \ref CapsApplicationAlbumEntry
CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
u64 unk_x28; ///< Unknown.
} CapsApplicationAlbumFileEntry;
/// ApplicationData
typedef struct {
u8 userdata[0x400]; ///< UserData.
@ -78,6 +130,37 @@ typedef struct {
u8 pad[7]; ///< Padding.
} CapsUserIdList;
// Get the ShimLibraryVersion.
/// LoadAlbumScreenShotImageOutputForApplication
typedef struct {
s64 width; ///< Width. Official sw copies this to a s32 output field.
s64 height; ///< Height. Official sw copies this to a s32 output field.
CapsScreenShotAttributeForApplication attr; ///< \ref CapsScreenShotAttributeForApplication
CapsApplicationData appdata; ///< \ref CapsApplicationData
u8 reserved[0xac]; ///< Unused.
} CapsLoadAlbumScreenShotImageOutputForApplication;
/// Gets the ShimLibraryVersion.
u64 capsGetShimLibraryVersion(void);
/// Gets the default start_datetime.
static inline CapsAlbumFileDateTime capsGetDefaultStartDateTime(void) {
return (CapsAlbumFileDateTime){.year = 1970, .month = 1, .day = 1};
}
/// Gets the default end_datetime.
static inline CapsAlbumFileDateTime capsGetDefaultEndDateTime(void) {
return (CapsAlbumFileDateTime){.year = 3000, .month = 1, .day = 1};
}
/// Convert a \ref CapsApplicationAlbumFileEntry to \ref CapsApplicationAlbumEntry.
static inline void capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry(CapsApplicationAlbumEntry *out, CapsApplicationAlbumFileEntry *in) {
*out = in->entry;
}
/// Convert a \ref CapsApplicationAlbumEntry to \ref CapsApplicationAlbumFileEntry. Should only be used on [7.0.0+].
static inline void capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry(CapsApplicationAlbumFileEntry *out, CapsApplicationAlbumEntry *in) {
out->entry = *in;
out->datetime = in->v1.datetime;
out->unk_x28 = 0;
}

View File

@ -11,7 +11,11 @@
/// Initialize caps:sc. Only available on [2.0.0+].
Result capsscInitialize(void);
/// Exit caps:sc.
void capsscExit(void);
/// Gets the Service for caps:sc.
Service* capsscGetServiceSession(void);
/**

View File

@ -74,7 +74,7 @@ Result capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreen
* @param[in] size Size of the buffer, must be at least 0x384000.
* @param[in] attr \ref CapsScreenShotAttribute
* @param[in] reportoption \ref AlbumReportOption
* @parma[in] appdata \ref CapsApplicationData
* @param[in] appdata \ref CapsApplicationData
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationData *appdata, CapsApplicationAlbumEntry *out);
@ -86,7 +86,7 @@ Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreen
* @param[in] size Size of the buffer, must be at least 0x384000.
* @param[in] attr \ref CapsScreenShotAttribute
* @param[in] reportoption \ref AlbumReportOption
* @parma[in] list \ref CapsUserIdList
* @param[in] list \ref CapsUserIdList
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotEx2(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsUserIdList *list, CapsApplicationAlbumEntry *out);

View File

@ -0,0 +1,172 @@
/**
* @file capsu.h
* @brief Application Album (caps:u) service IPC wrapper.
* This is only usable with AlbumFiles associated with the current Application host title.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../services/sm.h"
#include "../services/caps.h"
/// Initialize caps:u. Only available on [5.0.0+].
Result capsuInitialize(void);
/// Exit caps:u.
void capsuExit(void);
/// Gets the Service for caps:u.
Service* capsuGetServiceSession(void);
/// Gets the Service for IAlbumAccessorApplicationSession, only initialized after \ref capsuOpenAlbumMovieStream (unaffected by using \ref capsuCloseAlbumMovieStream).
Service* capsuGetServiceSession_Accessor(void);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry.
* @note On [6.0.0+] this uses GetAlbumFileList1AafeAruidDeprecated, otherwise this uses GetAlbumFileList0AafeAruidDeprecated.
* @note This is an old version of \ref capsuGetAlbumFileList3.
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u64 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
* @note Only available on [6.0.0+].
* @note This is an old version of \ref capsuGetAlbumFileList4.
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] userID userID.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u128 userID, u64 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumEntry.
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated1 instead.
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u64 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated2 instead.
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] userID userID.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u128 userID, u64 *total_entries);
/**
* @brief Deletes the specified AlbumFile.
* @param[in] type \ref CapsContentType, must match ::CapsContentType_ExtraMovie.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
*/
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry);
/**
* @brief Gets the filesize for the entire specified AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[out] size Output filesize.
*/
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size);
/**
* @brief Load the ScreenShotImage for the specified AlbumFile.
* @param[out] width Output image width. Optional, can be NULL.
* @param[out] height Output image height. Optional, can be NULL.
* @param[out] attr \ref CapsScreenShotAttributeForApplication
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
* @param[out] image RGBA8 image output buffer.
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 1280x720.
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[in] option \ref CapsScreenShotDecodeOption
*/
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
/**
* @brief Load the ScreenShotThumbnailImage for the specified AlbumFile.
* @param[out] width Output image width. Optional, can be NULL.
* @param[out] height Output image height. Optional, can be NULL.
* @param[out] attr \ref CapsScreenShotAttributeForApplication
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
* @param[out] image RGBA8 image output buffer.
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 320x180.
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[in] option \ref CapsScreenShotDecodeOption
*/
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
/**
* @brief PrecheckToCreateContents. Official sw only uses this with ::CapsContentType_ExtraMovie.
* @param[in] type \ref CapsContentType
* @param[in] unk Unknown.
*/
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk);
/**
* @brief Opens an AlbumMovieStream.
* @note This opens IAlbumAccessorApplicationSession if not previously opened, it's closed during \ref capsuExit.
* @note Up to 4 streams can be open at the same time. Multiple streams can be open at the same time for the same \ref CapsApplicationAlbumFileEntry.
* @param[out] stream Stream handle.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
*/
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry);
/**
* @brief Closes an AlbumMovieStream.
* @param[in] stream Stream handle.
*/
Result capsuCloseAlbumMovieStream(u64 stream);
/**
* @brief Gets the data size of an AlbumMovieStream.
* @param[in] stream Stream handle.
* @param[out] size Size of the actual MP4, without the JPEG at the end.
*/
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size);
/**
* @brief Reads data from an AlbumMovieStream.
* @note offset(+size) must not be negative. offset and size must be aligned to 0x40000-bytes.
* @note When offset(+size) goes beyond the size from \ref capsuGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size.
* @param[in] stream Stream handle.
* @param[in] offset Offset.
* @param[out] Output data buffer.
* @param[in] size Data buffer size.
* @param[out] actual_size Actual read size.
*/
Result capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size);
/**
* @brief Gets the BrokenReason for an AlbumMovieStream.
* @note Official sw doesn't use this.
* @param[in] stream Stream handle.
*/
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream);

761
nx/source/services/capsu.c Normal file
View File

@ -0,0 +1,761 @@
#include <string.h>
#include <time.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h"
#include "services/applet.h"
#include "services/caps.h"
#include "services/capsu.h"
#include "services/sm.h"
static Service g_capsuSrv;
static Service g_capsuAccessor;
static u64 g_capsuRefCnt;
static Result _capsuSetShimLibraryVersion(u64 version);
Result capsuInitialize(void) {
Result rc=0;
atomicIncrement64(&g_capsuRefCnt);
if (serviceIsActive(&g_capsuSrv))
return 0;
if (hosversionBefore(5,0,0))
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsuSrv, "caps:u");
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capsuSetShimLibraryVersion(capsGetShimLibraryVersion());
if (R_FAILED(rc)) capsuExit();
return rc;
}
void capsuExit(void) {
if (atomicDecrement64(&g_capsuRefCnt) == 0) {
serviceClose(&g_capsuAccessor);
serviceClose(&g_capsuSrv);
}
}
Service* capsuGetServiceSession(void) {
return &g_capsuSrv;
}
Service* capsuGetServiceSession_Accessor(void) {
return &g_capsuAccessor;
}
static Result _capsuCmdInU64(Service* srv, u64 inval, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 inval;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->inval = inval;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _capsuSetShimLibraryVersion(u64 version) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 version;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 32;
raw->version = version;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _capsuGetAlbumFileList0AafeAruidDeprecated(void* entries, size_t entrysize, size_t count, u8 type, u64 start_timestamp, u64 end_timestamp, u64 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 type;
u64 start_timestamp;
u64 end_timestamp;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
ipcAddRecvBuffer(&c, entries, count*entrysize, BufferType_Normal);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 102;
raw->type = type;
raw->start_timestamp = start_timestamp;
raw->end_timestamp = end_timestamp;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 total_entries;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
}
return rc;
}
static Result _capsuDeleteAlbumFileByAruid(u64 cmd_id, u8 type, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 type;
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->type = type;
raw->entry = *entry;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _capsuGetAlbumFileSizeByAruid(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 104;
raw->entry = *entry;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 size;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && size) *size = resp->size;
}
return rc;
}
static Result _capsuPrecheckToCreateContentsByAruid(u8 type, u64 unk) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 type;
u64 unk;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 130;
raw->type = type;
raw->unk = unk;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _capsuLoadAlbumScreenShotImageByAruid(u64 cmd_id, CapsLoadAlbumScreenShotImageOutputForApplication *out, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
CapsApplicationAlbumFileEntry entry;
CapsScreenShotDecodeOption option;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
ipcAddRecvBuffer(&c, out, sizeof(*out), BufferType_Normal);
ipcAddRecvBuffer(&c, image, image_size, BufferType_Type1);
ipcAddRecvBuffer(&c, workbuf, workbuf_size, BufferType_Normal);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->entry = *entry;
raw->option = *option;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _capsuGetAlbumFileListAaeAruid(u64 cmd_id, void* entries, size_t entrysize, size_t count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u64 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 type;
CapsAlbumFileDateTime start_datetime;
CapsAlbumFileDateTime end_datetime;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
ipcAddRecvBuffer(&c, entries, count*entrysize, BufferType_Normal);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->type = type;
raw->start_datetime = *start_datetime;
raw->end_datetime = *end_datetime;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 total_entries;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
}
return rc;
}
static Result _capsuGetAlbumFileListAaeUidAruid(u64 cmd_id, void* entries, size_t entrysize, size_t count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u128 userID, u64 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 type;
CapsAlbumFileDateTime start_datetime;
CapsAlbumFileDateTime end_datetime;
u8 pad[6];
union { u128 userID; } PACKED;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
ipcAddRecvBuffer(&c, entries, count*entrysize, BufferType_Normal);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->type = type;
raw->start_datetime = *start_datetime;
raw->end_datetime = *end_datetime;
raw->userID = userID;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 total_entries;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
}
return rc;
}
static Result _capsuOpenAccessorSessionForApplication(Service* srv_out, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 60002;
raw->entry = *entry;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && srv_out) {
serviceCreateSubservice(srv_out, &g_capsuSrv, &r, 0);
}
}
return rc;
}
static Result _capsuOpenAlbumMovieReadStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_capsuAccessor, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2001;
raw->entry = *entry;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capsuAccessor);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 stream;
} *resp;
serviceIpcParse(&g_capsuAccessor, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && stream) *stream = resp->stream;
}
return rc;
}
static Result _capsuGetAlbumMovieReadStreamMovieDataSize(u64 stream, u64 *size) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 stream;
} *raw;
raw = serviceIpcPrepareHeader(&g_capsuAccessor, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2003;
raw->stream = stream;
Result rc = serviceIpcDispatch(&g_capsuAccessor);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 size;
} *resp;
serviceIpcParse(&g_capsuAccessor, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && size) *size = resp->size;
}
return rc;
}
static Result _capsuReadMovieDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 stream;
s64 offset;
} *raw;
ipcAddRecvBuffer(&c, buffer, size, BufferType_Normal);
raw = serviceIpcPrepareHeader(&g_capsuAccessor, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2004;
raw->stream = stream;
raw->offset = offset;
Result rc = serviceIpcDispatch(&g_capsuAccessor);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 actual_size;
} *resp;
serviceIpcParse(&g_capsuAccessor, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && actual_size) *actual_size = resp->actual_size;
}
return rc;
}
static inline u64 _capsuMakeTimestamp(const CapsAlbumFileDateTime *datetime) {
struct tm tmptm = {.tm_sec = datetime->second, .tm_min = datetime->minute, .tm_hour = datetime->hour,
.tm_mday = datetime->day, .tm_mon = datetime->month, .tm_year = datetime->year - 1900};
return mktime(&tmptm);
}
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u64 *total_entries) {
u64 start_timestamp = 0x386BF200;
u64 end_timestamp = 0xF4865700;
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
if (hosversionBefore(6,0,0)) { // GetAlbumFileListDeprecated0
if (start_datetime) start_timestamp = _capsuMakeTimestamp(start_datetime);
if (end_datetime) end_timestamp = _capsuMakeTimestamp(end_datetime);
return _capsuGetAlbumFileList0AafeAruidDeprecated(entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_timestamp, end_timestamp, total_entries);
}
return _capsuGetAlbumFileListAaeAruid(140, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
}
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u128 userID, u64 *total_entries) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeUidAruid(141, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
}
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u64 *total_entries) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeAruid(142, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
}
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, size_t count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, u128 userID, u64 *total_entries) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeUidAruid(143, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
}
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry) {
return _capsuDeleteAlbumFileByAruid(103, type, entry);
}
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
return _capsuGetAlbumFileSizeByAruid(entry, size);
}
static void _capsuProcessImageOutput(CapsLoadAlbumScreenShotImageOutputForApplication *out, s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size) {
if (out==NULL) return;
if (width) *width = out->width;
if (height) *height = out->height;
if (attr) memcpy(attr, &out->attr, sizeof(out->attr));
if (userdata && userdata_maxsize) {
memset(userdata, 0, userdata_maxsize);
if (userdata_maxsize > sizeof(out->appdata.userdata)) userdata_maxsize = sizeof(out->appdata.userdata);
if (userdata_maxsize > out->appdata.size) userdata_maxsize = out->appdata.size;
memcpy(userdata, out->appdata.userdata, userdata_maxsize);
}
if (userdata_size) *userdata_size = out->appdata.size > sizeof(out->appdata.userdata) ? sizeof(out->appdata.userdata) : out->appdata.size;
}
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
Result rc=0;
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
rc = _capsuLoadAlbumScreenShotImageByAruid(110, &out, image, image_size, workbuf, workbuf_size, entry, option);
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
return rc;
}
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
Result rc=0;
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
rc = _capsuLoadAlbumScreenShotImageByAruid(120, &out, image, image_size, workbuf, workbuf_size, entry, option);
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
return rc;
}
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk) {
return _capsuPrecheckToCreateContentsByAruid(type, unk);
}
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
Result rc=0;
if (!serviceIsActive(&g_capsuAccessor)) rc =_capsuOpenAccessorSessionForApplication(&g_capsuAccessor, entry);
if (R_SUCCEEDED(rc)) rc = _capsuOpenAlbumMovieReadStream(stream, entry);
return rc;
}
Result capsuCloseAlbumMovieStream(u64 stream) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuCmdInU64(&g_capsuAccessor, stream, 2002);
}
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuGetAlbumMovieReadStreamMovieDataSize(stream, size);
}
Result capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuReadMovieDataFromAlbumMovieReadStream(stream, offset, buffer, size, actual_size);
}
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuCmdInU64(&g_capsuAccessor, stream, 2005);
}