#define NX_SERVICE_ASSUME_NON_DOMAIN #include #include "service_guard.h" #include "runtime/hosversion.h" #include "services/ncm.h" static Service g_ncmSrv; NX_GENERATE_SERVICE_GUARD(ncm); Result _ncmInitialize(void) { return smGetService(&g_ncmSrv, "ncm"); } void _ncmCleanup(void) { serviceClose(&g_ncmSrv); } Service* ncmGetServiceSession(void) { return &g_ncmSrv; } static Result _ncmGetInterfaceInU8(Service* srv_out, u8 inval, u32 cmd_id) { return serviceDispatchIn(&g_ncmSrv, cmd_id, inval, .out_num_objects = 1, .out_objects = srv_out, ); } static Result _ncmCmdNoIO(Service* srv, u32 cmd_id) { return serviceDispatch(srv, cmd_id); } static Result _ncmCmdNoInOutU64(Service* srv, u64* outval, u32 cmd_id) { return serviceDispatchOut(srv, cmd_id, *outval); } static Result _ncmCmdOutPlaceHolderId(Service* srv, NcmPlaceHolderId* outval, u32 cmd_id) { return serviceDispatchOut(srv, cmd_id, *outval); } static Result _ncmCmdInU8(Service* srv, u8 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } static Result _ncmCmdInU32(Service* srv, u32 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } static Result _ncmCmdInContentId(Service* srv, const NcmContentId* inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, *inval); } static Result _ncmCmdInPlaceHolderId(Service* srv, const NcmPlaceHolderId* inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, *inval); } static Result _ncmCmdInContentIdOutU64(Service* srv, const NcmContentId* inval, u64* outval, u32 cmd_id) { return serviceDispatchInOut(srv, cmd_id, *inval, *outval); } static Result _ncmCmdInPlaceHolderIdOutU64(Service* srv, const NcmPlaceHolderId* inval, u64* outval, u32 cmd_id) { return serviceDispatchInOut(srv, cmd_id, *inval, *outval); } Result ncmCreateContentStorage(NcmStorageId storage_id) { return _ncmCmdInU8(&g_ncmSrv, storage_id, 0); } Result ncmCreateContentMetaDatabase(NcmStorageId storage_id) { return _ncmCmdInU8(&g_ncmSrv, storage_id, 1); } Result ncmVerifyContentStorage(NcmStorageId storage_id) { return _ncmCmdInU8(&g_ncmSrv, storage_id, 2); } Result ncmVerifyContentMetaDatabase(NcmStorageId storage_id) { return _ncmCmdInU8(&g_ncmSrv, storage_id, 3); } Result ncmOpenContentStorage(NcmContentStorage* out_content_storage, NcmStorageId storage_id) { return _ncmGetInterfaceInU8(&out_content_storage->s, storage_id, 4); } Result ncmOpenContentMetaDatabase(NcmContentMetaDatabase* out_content_meta_database, NcmStorageId storage_id) { return _ncmGetInterfaceInU8(&out_content_meta_database->s, storage_id, 5); } Result ncmCloseContentStorageForcibly(NcmStorageId storage_id) { if (hosversionAtLeast(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 6); } Result ncmCloseContentMetaDatabaseForcibly(NcmStorageId storage_id) { if (hosversionAtLeast(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 7); } Result ncmCleanupContentMetaDatabase(NcmStorageId storage_id) { return _ncmCmdInU8(&g_ncmSrv, storage_id, 8); } Result ncmActivateContentStorage(NcmStorageId storage_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 9); } Result ncmInactivateContentStorage(NcmStorageId storage_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 10); } Result ncmActivateContentMetaDatabase(NcmStorageId storage_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 11); } Result ncmInactivateContentMetaDatabase(NcmStorageId storage_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU8(&g_ncmSrv, storage_id, 12); } Result ncmInvalidateRightsIdCache(void) { if (hosversionBefore(9,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoIO(&g_ncmSrv, 13); } Result ncmActivateFsContentStorage(FsContentStorageId fs_storage_id) { if (!hosversionIsAtmosphere() && hosversionBefore(16,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInU32(&g_ncmSrv, fs_storage_id, 15); } void ncmContentStorageClose(NcmContentStorage* cs) { serviceClose(&cs->s); } Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmPlaceHolderId* out_id) { return _ncmCmdOutPlaceHolderId(&cs->s, out_id, 0); } Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmContentId* content_id, const NcmPlaceHolderId* placeholder_id, s64 size) { if (hosversionBefore(16,0,0)) { const struct { NcmContentId content_id; NcmPlaceHolderId placeholder_id; s64 size; } in = { *content_id, *placeholder_id, size }; return serviceDispatchIn(&cs->s, 1, in); } else { const struct { NcmPlaceHolderId placeholder_id; NcmContentId content_id; s64 size; } in = { *placeholder_id, *content_id, size }; return serviceDispatchIn(&cs->s, 1, in); } } Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmPlaceHolderId* placeholder_id) { return _ncmCmdInPlaceHolderId(&cs->s, placeholder_id, 2); } Result ncmContentStorageHasPlaceHolder(NcmContentStorage* cs, bool* out, const NcmPlaceHolderId* placeholder_id) { u8 tmp=0; Result rc = serviceDispatchInOut(&cs->s, 3, *placeholder_id, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmPlaceHolderId* placeholder_id, u64 offset, const void* data, size_t data_size) { const struct { NcmPlaceHolderId placeholder_id; u64 offset; } in = { *placeholder_id, offset }; return serviceDispatchIn(&cs->s, 4, in, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { data, data_size } }, ); } Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmContentId* content_id, const NcmPlaceHolderId* placeholder_id) { if (hosversionBefore(16,0,0)) { const struct { NcmContentId content_id; NcmPlaceHolderId placeholder_id; } in = { *content_id, *placeholder_id }; return serviceDispatchIn(&cs->s, 5, in); } else { const struct { NcmPlaceHolderId placeholder_id; NcmContentId content_id; } in = { *placeholder_id, *content_id }; return serviceDispatchIn(&cs->s, 5, in); } } Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmContentId* content_id) { return _ncmCmdInContentId(&cs->s, content_id, 6); } Result ncmContentStorageHas(NcmContentStorage* cs, bool* out, const NcmContentId* content_id) { u8 tmp=0; Result rc = serviceDispatchInOut(&cs->s, 7, *content_id, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result ncmContentStorageGetPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmContentId* content_id) { char tmpbuf[0x300]={0}; Result rc = serviceDispatchIn(&cs->s, 8, *content_id, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, .buffers = { { tmpbuf, sizeof(tmpbuf) } }, ); if (R_SUCCEEDED(rc) && out_path) { strncpy(out_path, tmpbuf, out_size-1); out_path[out_size-1] = 0; } return rc; } Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmPlaceHolderId* placeholder_id) { char tmpbuf[0x300]={0}; Result rc = serviceDispatchIn(&cs->s, 9, *placeholder_id, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, .buffers = { { tmpbuf, sizeof(tmpbuf) } }, ); if (R_SUCCEEDED(rc) && out_path) { strncpy(out_path, tmpbuf, out_size-1); out_path[out_size-1] = 0; } return rc; } Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs) { return _ncmCmdNoIO(&cs->s, 10); } Result ncmContentStorageListPlaceHolder(NcmContentStorage* cs, NcmPlaceHolderId* out_ids, s32 count, s32* out_count) { return serviceDispatchOut(&cs->s, 11, *out_count, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_ids, count*sizeof(NcmPlaceHolderId) } }, ); } Result ncmContentStorageGetContentCount(NcmContentStorage* cs, s32* out_count) { return serviceDispatchOut(&cs->s, 12, *out_count); } Result ncmContentStorageListContentId(NcmContentStorage* cs, NcmContentId* out_ids, s32 count, s32* out_count, s32 start_offset) { return serviceDispatchInOut(&cs->s, 13, start_offset, *out_count, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_ids, count*sizeof(NcmContentId) } }, ); } Result ncmContentStorageGetSizeFromContentId(NcmContentStorage* cs, s64* out_size, const NcmContentId* content_id) { return _ncmCmdInContentIdOutU64(&cs->s, content_id, (u64*)out_size, 14); } Result ncmContentStorageDisableForcibly(NcmContentStorage* cs) { return _ncmCmdNoIO(&cs->s, 15); } Result ncmContentStorageRevertToPlaceHolder(NcmContentStorage* cs, const NcmPlaceHolderId* placeholder_id, const NcmContentId* old_content_id, const NcmContentId* new_content_id) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(16,0,0)) { const struct { NcmContentId old_content_id; NcmContentId new_content_id; NcmPlaceHolderId placeholder_id; } in = { *old_content_id, *new_content_id, *placeholder_id }; return serviceDispatchIn(&cs->s, 16, in); } else { const struct { NcmPlaceHolderId placeholder_id; NcmContentId old_content_id; NcmContentId new_content_id; } in = { *placeholder_id, *old_content_id, *new_content_id }; return serviceDispatchIn(&cs->s, 16, in); } } Result ncmContentStorageSetPlaceHolderSize(NcmContentStorage* cs, const NcmPlaceHolderId* placeholder_id, s64 size) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { NcmPlaceHolderId placeholder_id; s64 size; } in = { *placeholder_id, size }; return serviceDispatchIn(&cs->s, 17, in); } Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, void* out_data, size_t out_data_size, const NcmContentId* content_id, s64 offset) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { NcmContentId content_id; s64 offset; } in = { *content_id, offset }; return serviceDispatchIn(&cs->s, 18, in, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_data, out_data_size } }, ); } Result ncmContentStorageGetRightsIdFromPlaceHolderId(NcmContentStorage* cs, NcmRightsId* out_rights_id, const NcmPlaceHolderId* placeholder_id, FsContentAttributes attr) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { NcmPlaceHolderId placeholder_id; u8 attr; } in = { *placeholder_id, attr }; if (hosversionBefore(3,0,0)) return serviceDispatchInOut(&cs->s, 19, in, out_rights_id->rights_id); else return serviceDispatchInOut(&cs->s, 19, in, *out_rights_id); } Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, NcmRightsId* out_rights_id, const NcmContentId* content_id, FsContentAttributes attr) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); memset(out_rights_id, 0, sizeof(*out_rights_id)); const struct { NcmContentId content_id; u8 attr; } in = { *content_id, attr }; if (hosversionBefore(3,0,0)) return serviceDispatchInOut(&cs->s, 20, in, out_rights_id->rights_id); else return serviceDispatchInOut(&cs->s, 20, in, *out_rights_id); } Result ncmContentStorageWriteContentForDebug(NcmContentStorage* cs, const NcmContentId* content_id, s64 offset, const void* data, size_t data_size) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { NcmContentId content_id; s64 offset; } in = { *content_id, offset }; return serviceDispatchIn(&cs->s, 21, in, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { data, data_size } }, ); } Result ncmContentStorageGetFreeSpaceSize(NcmContentStorage* cs, s64* out_size) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoInOutU64(&cs->s, (u64*)out_size, 22); } Result ncmContentStorageGetTotalSpaceSize(NcmContentStorage* cs, s64* out_size) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoInOutU64(&cs->s, (u64*)out_size, 23); } Result ncmContentStorageFlushPlaceHolder(NcmContentStorage* cs) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoIO(&cs->s, 24); } Result ncmContentStorageGetSizeFromPlaceHolderId(NcmContentStorage* cs, s64* out_size, const NcmPlaceHolderId* placeholder_id) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdInPlaceHolderIdOutU64(&cs->s, placeholder_id, (u64*)out_size, 25); } Result ncmContentStorageRepairInvalidFileAttribute(NcmContentStorage* cs) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoIO(&cs->s, 26); } Result ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(NcmContentStorage* cs, NcmRightsId* out_rights_id, const NcmPlaceHolderId* placeholder_id, const NcmContentId* cache_content_id, FsContentAttributes attr) { if (hosversionBefore(8,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(16,0,0)) { const struct { NcmContentId cache_content_id; NcmPlaceHolderId placeholder_id; } in = { *cache_content_id, *placeholder_id }; return serviceDispatchInOut(&cs->s, 27, in, *out_rights_id); } else { const struct { NcmPlaceHolderId placeholder_id; NcmContentId cache_content_id; u8 attr; } in = { *placeholder_id, *cache_content_id, attr }; return serviceDispatchInOut(&cs->s, 27, in, *out_rights_id); } } Result ncmContentStorageRegisterPath(NcmContentStorage* cs, const NcmContentId* content_id, const char *path) { if (hosversionBefore(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); char send_path[FS_MAX_PATH] = {0}; strncpy(send_path, path, FS_MAX_PATH-1); send_path[FS_MAX_PATH-1] = 0; return serviceDispatchIn(&cs->s, 28, *content_id, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer }, .buffers = { { send_path, FS_MAX_PATH } }, ); } Result ncmContentStorageClearRegisteredPath(NcmContentStorage* cs) { if (hosversionBefore(13,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _ncmCmdNoIO(&cs->s, 29); } void ncmContentMetaDatabaseClose(NcmContentMetaDatabase* db) { serviceClose(&db->s); } Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, const void* data, u64 data_size) { return serviceDispatchIn(&db->s, 0, *key, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { data, data_size } }, ); } Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u64* out_size, void* out_data, u64 out_data_size) { return serviceDispatchInOut(&db->s, 1, *key, *out_size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_data, out_data_size } }, ); } Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmContentMetaKey *key) { return serviceDispatchIn(&db->s, 2, *key); } Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmContentId* out_content_id, const NcmContentMetaKey* key, NcmContentType type) { const struct { u8 type; u8 padding[7]; NcmContentMetaKey key; } in = { type, {0}, *key }; return serviceDispatchInOut(&db->s, 3, in, *out_content_id); } Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, s32* out_entries_written, NcmContentInfo* out_info, s32 count, const NcmContentMetaKey* key, s32 start_index) { const struct { s32 start_index; u32 pad; NcmContentMetaKey key; } in = { start_index, 0, *key }; return serviceDispatchInOut(&db->s, 4, in, *out_entries_written, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_info, count*sizeof(NcmContentInfo) } }, ); } Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, s32* out_entries_total, s32* out_entries_written, NcmContentMetaKey* out_keys, s32 count, NcmContentMetaType meta_type, u64 id, u64 id_min, u64 id_max, NcmContentInstallType install_type) { const struct { u8 meta_type; u8 install_type; u8 padding[6]; u64 id; u64 id_min; u64 id_max; } in = { meta_type, install_type, {0}, id, id_min, id_max }; struct { s32 out_entries_total; s32 out_entries_written; } out; Result rc = serviceDispatchInOut(&db->s, 5, in, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_keys, count*sizeof(NcmContentMetaKey) } }, ); if (R_SUCCEEDED(rc)) { if (out_entries_total) *out_entries_total = out.out_entries_total; if (out_entries_written) *out_entries_written = out.out_entries_written; } return rc; } Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, NcmContentMetaKey* out_key, u64 id) { return serviceDispatchInOut(&db->s, 6, id, *out_key); } Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, s32* out_entries_total, s32* out_entries_written, NcmApplicationContentMetaKey* out_keys, s32 count, NcmContentMetaType meta_type) { struct { s32 out_entries_total; s32 out_entries_written; } out; Result rc = serviceDispatchInOut(&db->s, 7, meta_type, out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_keys, count*sizeof(NcmApplicationContentMetaKey) } }, ); if (R_SUCCEEDED(rc)) { if (out_entries_total) *out_entries_total = out.out_entries_total; if (out_entries_written) *out_entries_written = out.out_entries_written; } return rc; } Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key) { u8 tmp=0; Result rc = serviceDispatchInOut(&db->s, 8, *key, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result ncmContentMetaDatabaseHasAll(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* keys, s32 count) { u8 tmp=0; Result rc = serviceDispatchOut(&db->s, 9, *out, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { keys, count*sizeof(NcmContentMetaKey) } }, ); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result ncmContentMetaDatabaseGetSize(NcmContentMetaDatabase* db, u64* out_size, const NcmContentMetaKey* key) { return serviceDispatchInOut(&db->s, 10, *key, *out_size); } Result ncmContentMetaDatabaseGetRequiredSystemVersion(NcmContentMetaDatabase* db, u32* out_version, const NcmContentMetaKey* key) { return serviceDispatchInOut(&db->s, 11, *key, *out_version); } Result ncmContentMetaDatabaseGetPatchContentMetaId(NcmContentMetaDatabase* db, u64* out_patch_id, const NcmContentMetaKey* key) { return serviceDispatchInOut(&db->s, 12, *key, *out_patch_id); } Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db) { return _ncmCmdNoIO(&db->s, 13); } Result ncmContentMetaDatabaseLookupOrphanContent(NcmContentMetaDatabase* db, bool* out_orphaned, const NcmContentId* content_ids, s32 count) { return serviceDispatch(&db->s, 14, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, SfBufferAttr_HipcMapAlias | SfBufferAttr_In, }, .buffers = { { out_orphaned, count }, { content_ids, count*sizeof(NcmContentId) }, }, ); } Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db) { return _ncmCmdNoIO(&db->s, 15); } Result ncmContentMetaDatabaseHasContent(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key, const NcmContentId* content_id) { const struct { NcmContentId content_id; NcmContentMetaKey key; } in = { *content_id, *key }; u8 tmp=0; Result rc = serviceDispatchInOut(&db->s, 16, in, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result ncmContentMetaDatabaseListContentMetaInfo(NcmContentMetaDatabase* db, s32* out_entries_written, void* out_meta_info, s32 count, const NcmContentMetaKey* key, s32 start_index) { const struct { s32 start_index; u32 padding; NcmContentMetaKey key; } in = { start_index, 0, *key }; return serviceDispatchInOut(&db->s, 17, in, *out_entries_written, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, .buffers = { { out_meta_info, count*sizeof(NcmContentMetaInfo) } }, ); } Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u8* out) { return serviceDispatchInOut(&db->s, 18, *key, *out); } Result ncmContentMetaDatabaseGetRequiredApplicationVersion(NcmContentMetaDatabase* db, u32* out_version, const NcmContentMetaKey* key) { if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return serviceDispatchInOut(&db->s, 19, *key, *out_version); } Result ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(NcmContentMetaDatabase* db, NcmContentId* out_content_id, const NcmContentMetaKey* key, NcmContentType type, u8 id_offset) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); const struct { u8 type; u8 id_offset; u8 padding[6]; NcmContentMetaKey key; } in = { type, id_offset, {0}, *key }; return serviceDispatchInOut(&db->s, 20, in, *out_content_id); }