#define NX_SERVICE_ASSUME_NON_DOMAIN #include #include #include "service_guard.h" #include "runtime/hosversion.h" #include "services/applet.h" #include "services/capsa.h" static Service g_capsaSrv; static Service g_capsaAccessor; NX_GENERATE_SERVICE_GUARD(capsa); Result _capsaInitialize(void) { return smGetService(&g_capsaSrv, "caps:a"); } void _capsaCleanup(void) { serviceClose(&g_capsaAccessor); serviceClose(&g_capsaSrv); } Service* capsaGetServiceSession(void) { return &g_capsaSrv; } Service* capsaGetServiceSession_Accessor(void) { return &g_capsaAccessor; } static Result _capsaCmdInU8NoOut(Service *srv, u8 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } Result capsaGetAlbumFileCount(CapsAlbumStorage storage, u64 *count) { u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 0, inval, *count); } Result capsaGetAlbumFileList(CapsAlbumStorage storage, u64 *out, CapsAlbumEntry *entries, u64 count) { u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 1, inval, *out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { entries, count * sizeof(CapsAlbumEntry) } }, ); } Result capsaLoadAlbumFile(const CapsAlbumFileId *file_id, u64 *out_size, void* filebuf, u64 filebuf_size) { return serviceDispatchInOut(&g_capsaSrv, 2, *file_id, *out_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { filebuf, filebuf_size } }, ); } Result capsaDeleteAlbumFile(const CapsAlbumFileId *file_id) { return serviceDispatchIn(&g_capsaSrv, 3, *file_id); } Result capsaStorageCopyAlbumFile(const CapsAlbumFileId *file_id, CapsAlbumStorage dst_storage) { const struct { u8 storage; u8 pad_x1[0x7]; CapsAlbumFileId file_id; } in = { dst_storage, {0}, *file_id }; return serviceDispatchIn(&g_capsaSrv, 4, in); } Result capsaIsAlbumMounted(CapsAlbumStorage storage, bool *is_mounted) { u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 5, inval, *is_mounted); } Result capsaGetAlbumUsage(CapsAlbumStorage storage, CapsAlbumUsage2 *out) { u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 6, inval, *out); } Result capsaGetAlbumFileSize(const CapsAlbumFileId *file_id, u64 *size) { return serviceDispatchInOut(&g_capsaSrv, 7, *file_id, *size); } Result capsaLoadAlbumFileThumbnail(const CapsAlbumFileId *file_id, u64 *out_size, void* image, u64 image_size) { return serviceDispatchInOut(&g_capsaSrv, 8, *file_id, *out_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { image, image_size } }, ); } static Result _capsaLoadAlbumScreenshot(u64 *width, u64 *height, const CapsAlbumFileId *file_id, void* image, u64 image_size, void* workbuf, u64 workbuf_size, u32 cmd_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); struct { u64 width; u64 height; } out; Result rc = serviceDispatchInOut(&g_capsaSrv, cmd_id, *file_id, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_HipcMapTransferAllowsNonSecure, SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { image, image_size }, { workbuf, workbuf_size } }, ); if (R_SUCCEEDED(rc)) { if (width) *width = out.width; if (height) *height = out.height; } return rc; } Result capsaLoadAlbumScreenShotImage(u64 *width, u64 *height, const CapsAlbumFileId *file_id, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenshot(width, height, file_id, image, image_size, workbuf, workbuf_size, 9); } Result capsaLoadAlbumScreenShotThumbnailImage(u64 *width, u64 *height, const CapsAlbumFileId *file_id, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenshot(width, height, file_id, image, image_size, workbuf, workbuf_size, 10); } static Result _capsaLoadAlbumScreenshotEx(u64 *width, u64 *height, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size, u32 cmd_id) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsAlbumFileId file_id; CapsScreenShotDecodeOption opts; } in = { *file_id, *opts }; struct { u64 width; u64 height; } out; Result rc = serviceDispatchInOut(&g_capsaSrv, cmd_id, in, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_HipcMapTransferAllowsNonSecure, SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { image, image_size }, { workbuf, workbuf_size } }, ); if (R_SUCCEEDED(rc)) { if (width) *width = out.width; if (height) *height = out.height; } return rc; } Result capsaLoadAlbumScreenShotImageEx(u64 *width, u64 *height, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenshotEx(width, height, file_id, opts, image, image_size, workbuf, workbuf_size, 12); } Result capsaLoadAlbumScreenShotThumbnailImageEx(u64 *width, u64 *height, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenshotEx(width, height, file_id, opts, image, image_size, workbuf, workbuf_size, 13); } Result _capsaLoadAlbumScreenShotEx0(u64 *width, u64 *height, CapsScreenShotAttribute *attr, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size, u32 cmd_id) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsAlbumFileId file_id; CapsScreenShotDecodeOption opts; } in = { *file_id, *opts }; struct { CapsScreenShotAttribute attr; s64 width; s64 height; } out = {0}; Result rc = serviceDispatchInOut(&g_capsaSrv, cmd_id, in, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_HipcMapTransferAllowsNonSecure, SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { image, image_size }, { workbuf, workbuf_size } }, ); if (R_SUCCEEDED(rc)) { if (attr) *attr = out.attr; if (width) *width = out.width; if (height) *height = out.height; } return rc; } Result capsaLoadAlbumScreenShotImageEx0(u64 *width, u64 *height, CapsScreenShotAttribute *attr, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenShotEx0(width, height, attr, file_id, opts, image, image_size, workbuf, workbuf_size, 14); } Result capsaGetAlbumUsage3(CapsAlbumStorage storage, CapsAlbumUsage3 *out) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 15, inval, *out); } Result capsaGetAlbumMountResult(CapsAlbumStorage storage) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _capsaCmdInU8NoOut(&g_capsaSrv, storage, 16); } Result capsaGetAlbumUsage16(CapsAlbumStorage storage, CapsAlbumUsage16 *out) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); u8 inval = storage; return serviceDispatchInOut(&g_capsaSrv, 17, inval, *out); } Result capsaGetMinMaxAppletId(bool *success, u64* min, u64* max) { if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); u64 app_ids[2]; struct { bool success; u8 pad[0x3]; } out; Result rc = serviceDispatchOut(&g_capsaSrv, 18, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_HipcMapTransferAllowsNonSecure, }, .buffers = { { app_ids, sizeof(app_ids) }, }, ); if (R_SUCCEEDED(rc)) { if (min) *min = app_ids[0]; if (max) *max = app_ids[1]; if (success) *success = out.success; } return rc; } Result capsaGetAlbumFileCountEx0(CapsAlbumStorage storage, u8 flags, u64 *count) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); struct { u8 storage; u8 pad_x1[7]; u8 flags; u8 pad_x9[7]; } in = { storage, {0}, flags, {0} }; return serviceDispatchInOut(&g_capsaSrv, 100, in, *count); } Result capsaGetAlbumFileListEx0(CapsAlbumStorage storage, u8 flags, u64 *out, CapsAlbumEntry *entries, u64 count) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); struct { u8 storage; u8 pad_x1[7]; u8 contents; u8 pad_x9[7]; } in = { storage, {0}, flags, {0} }; return serviceDispatchInOut(&g_capsaSrv, 101, in, *out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { entries, count * sizeof(CapsAlbumEntry) } }, ); } Result _capsaGetLastOverlayThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size, u32 cmd_id) { return serviceDispatchOut(&g_capsaSrv, cmd_id, *data, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, }, .buffers = { { image, image_size }, }, ); } Result capsaGetLastOverlayScreenShotThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size) { return _capsaGetLastOverlayThumbnail(data, image, image_size, 301); } Result capsaGetLastOverlayMovieThumbnail(CapsOverlayThumbnailData *data, void* image, u64 image_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _capsaGetLastOverlayThumbnail(data, image, image_size, 302); } Result capsaGetAutoSavingStorage(CapsAlbumStorage *storage) { u8 tmpval = 0; Result rc = serviceDispatchOut(&g_capsaSrv, 401, tmpval); if (R_SUCCEEDED(rc)) { if (storage) *storage = tmpval; } return rc; } Result capsaGetRequiredStorageSpaceSizeToCopyAll(CapsAlbumStorage dst_storage, CapsAlbumStorage src_storage, u64 *out) { const struct { u8 dest; u8 src; } in = { dst_storage, src_storage }; return serviceDispatchInOut(&g_capsaSrv, 501, in, *out); } Result capsLoadAlbumScreenShotThumbnailImageEx0(u64 *width, u64 *height, CapsScreenShotAttribute *attr, const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenShotEx0(width, height, attr, file_id, opts, image, image_size, workbuf, workbuf_size, 1001); } Result _capsaLoadAlbumScreenShotEx1(const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, CapsLoadAlbumScreenShotImageOutput *out, void* image, u64 image_size, void* workbuf, u64 workbuf_size, u32 cmd_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { CapsAlbumFileId file_id; CapsScreenShotDecodeOption opts; } in = { *file_id, *opts }; return serviceDispatchIn(&g_capsaSrv, cmd_id, in, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_FixedSize, SfBufferAttr_HipcMapAlias | SfBufferAttr_Out | SfBufferAttr_HipcMapTransferAllowsNonSecure, SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out, sizeof(CapsLoadAlbumScreenShotImageOutput) }, { image, image_size }, { workbuf, workbuf_size } }, ); } Result capsaLoadAlbumScreenShotImageEx1(const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, CapsLoadAlbumScreenShotImageOutput *out, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenShotEx1(file_id, opts, out, image, image_size, workbuf, workbuf_size, 1002); } Result capsaLoadAlbumScreenShotThumbnailImageEx1(const CapsAlbumFileId *file_id, const CapsScreenShotDecodeOption *opts, CapsLoadAlbumScreenShotImageOutput *out, void* image, u64 image_size, void* workbuf, u64 workbuf_size) { return _capsaLoadAlbumScreenShotEx1(file_id, opts, out, image, image_size, workbuf, workbuf_size, 1003); } Result capsaForceAlbumUnmounted(CapsAlbumStorage storage) { return _capsaCmdInU8NoOut(&g_capsaSrv, storage, 8001); } Result capsaResetAlbumMountStatus(CapsAlbumStorage storage) { return _capsaCmdInU8NoOut(&g_capsaSrv, storage, 8002); } Result capsaRefreshAlbumCache(CapsAlbumStorage storage) { return _capsaCmdInU8NoOut(&g_capsaSrv, storage, 8011); } Result capsaGetAlbumCache(CapsAlbumStorage storage, CapsAlbumCache *cache) { return serviceDispatchInOut(&g_capsaSrv, 8012, storage, *cache); } Result capsaGetAlbumCacheEx(CapsAlbumStorage storage, CapsAlbumFileContents contents, CapsAlbumCache *cache) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); struct { u8 storage; u8 contents; } in = { storage, contents }; return serviceDispatchInOut(&g_capsaSrv, 8013, in, *cache); } static Result _capsaOpenAccessorSession(Service *srv_out) { u64 AppletResourceUserId = appletGetAppletResourceUserId(); return serviceDispatchIn(&g_capsaSrv, 60002, AppletResourceUserId, .in_send_pid = true, .out_num_objects = 1, .out_objects = srv_out, ); } static Result _capsaOpenAlbumMovieReadStream(u64 *stream, const CapsAlbumFileId *file_id) { return serviceDispatchInOut(&g_capsaAccessor, 2001, *file_id, *stream); } static Result _capsaReadMovieDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) { const struct { u64 stream; s64 offset; } in = { stream, offset }; return serviceDispatchInOut(&g_capsaAccessor, 2004, in, *actual_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { buffer, size } }, ); } static Result _capsaReadImageDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) { const struct { u64 stream; s64 offset; } in = { stream, offset }; return serviceDispatchInOut(&g_capsaAccessor, 2007, in, *actual_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { buffer, size } }, ); } Result capsaOpenAlbumMovieStream(u64 *stream, const CapsAlbumFileId *file_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); Result rc=0; if (!serviceIsActive(&g_capsaAccessor)) rc = _capsaOpenAccessorSession(&g_capsaAccessor); if (R_SUCCEEDED(rc)) rc = _capsaOpenAlbumMovieReadStream(stream, file_id); return rc; } Result capsaCloseAlbumMovieStream(u64 stream) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return serviceDispatchIn(&g_capsaAccessor, 2002, stream); } Result capsaGetAlbumMovieStreamSize(u64 stream, u64 *size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return serviceDispatchInOut(&g_capsaAccessor, 2003, stream, *size); } Result capsaReadMovieDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return _capsaReadMovieDataFromAlbumMovieReadStream(stream, offset, buffer, size, actual_size); } Result capsaGetAlbumMovieReadStreamBrokenReason(u64 stream) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return serviceDispatchIn(&g_capsaAccessor, 2005, stream); } Result capsaGetAlbumMovieReadStreamImageDataSize(u64 stream, u64 *size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return serviceDispatchInOut(&g_capsaAccessor, 2006, stream, *size); } Result capsaReadImageDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return _capsaReadImageDataFromAlbumMovieReadStream(stream, offset, buffer, size, actual_size); } Result capsaReadFileAttributeFromAlbumMovieReadStream(u64 stream, CapsScreenShotAttribute *attribute) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (!serviceIsActive(&g_capsaAccessor)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return serviceDispatchInOut(&g_capsaAccessor, 2008, stream, *attribute); }