diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index 969610a20..a15dd6362 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -656,6 +656,33 @@ Result nsRequestDownloadApplicationControlData(AsyncResult *a, u64 application_i */ Result nsListApplicationTitle(AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, void* buffer, size_t size); +/** + * @brief ListApplicationTitle2. Returns \ref NacpLanguageEntry matching currently set system language for each specified ApplicationId. + * @note The data available with \ref asyncValueGet is a s32 for the offset within the buffer where the output data is located, \ref asyncValueGetSize returns the total byte-size of the data located here. The data located here is the \ref NacpLanguageEntry for each specified ApplicationId. + * @note Only available on [20.0.0+]. + * @note NacpLanguageEntry is decompressed when necessary only on [21.0.0+]. + * @param[out] a \ref AsyncValue + * @param[in] source Source, official sw uses ::NsApplicationControlSource_Storage. + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the application_ids array in entries. + * @param buffer 0x1000-byte aligned buffer for TransferMemory. This buffer must not be accessed until the async operation finishes. + * @param[in] size 0x1000-byte aligned buffer size for TransferMemory. This must be at least: count*sizeof(\ref NacpLanguageEntry) + count*sizeof(u64) + count*sizeof(\ref NsApplicationControlData). + */ +Result nsListApplicationTitle2(AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, void* buffer, size_t size); + +/** + * @brief ListApplicationTitle3. Returns \ref NacpLanguageEntry matching currently set system language for each specified ApplicationId. + * @note The data available with \ref asyncValueGet is a s32 for the offset within the buffer where the output data is located, \ref asyncValueGetSize returns the total byte-size of the data located here. The data located here is the \ref NacpLanguageEntry for each specified ApplicationId. + * @note Only available on [20.0.0+]. + * @note NacpLanguageEntry is decompressed when necessary only on [21.0.0+]. + * @param[out] a \ref AsyncValue + * @param[in] application_ids Input array of ApplicationIds. + * @param[in] count Size of the application_ids array in entries. + * @param buffer 0x1000-byte aligned buffer for TransferMemory. This buffer must not be accessed until the async operation finishes. + * @param[in] size 0x1000-byte aligned buffer size for TransferMemory. This must be at least: count*sizeof(\ref NacpLanguageEntry) + count*sizeof(u64) + sizeof(\ref NsApplicationControlData). + */ +Result nsListApplicationTitle3(AsyncValue *a, const u64 *application_ids, s32 count, void* buffer, size_t size); + /** * @brief ListApplicationIcon * @note The data available with \ref asyncValueGet is a s32 for the offset within the buffer where the output data is located, \ref asyncValueGetSize returns the total byte-size of the data located here. This data is: an u64 for total entries, an array of u64s for each icon size, then the icon JPEGs for the specified ApplicationIds. diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index a1ec650e8..8a39079ad 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -980,10 +980,7 @@ Result nsRequestDownloadApplicationControlData(AsyncResult *a, u64 application_i return _nsManCmdInU64OutAsyncResult(a, application_id, 402); } -static Result _nsListApplicationTitleIcon(AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, TransferMemory *tmem, u32 cmd_id) { // [8.0.0+] - Service srv={0}; - Result rc = nsGetApplicationManagerInterface(&srv); - +static Result _nsListApplicationTitleIcon(Service* srv, AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, TransferMemory *tmem, u32 cmd_id) { const struct { u8 source; u8 pad[7]; @@ -992,7 +989,27 @@ static Result _nsListApplicationTitleIcon(AsyncValue *a, NsApplicationControlSou memset(a, 0, sizeof(*a)); Handle event = INVALID_HANDLE; - if (R_SUCCEEDED(rc)) rc = serviceDispatchIn(&srv, cmd_id, in, + Result rc = serviceDispatchIn(srv, cmd_id, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { application_ids, count*sizeof(u64) } }, + .in_num_handles = 1, + .in_handles = { tmem->handle }, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +static Result _nsListApplicationTitleIcon2(Service* srv, AsyncValue *a, const u64 *application_ids, s32 count, TransferMemory *tmem, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatchIn(srv, cmd_id, tmem->size, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { application_ids, count*sizeof(u64) } }, .in_num_handles = 1, @@ -1006,7 +1023,6 @@ static Result _nsListApplicationTitleIcon(AsyncValue *a, NsApplicationControlSou if (R_SUCCEEDED(rc)) eventLoadRemote(&a->event, event, false); - serviceClose(&srv); return rc; } @@ -1016,23 +1032,84 @@ Result nsListApplicationTitle(AsyncValue *a, NsApplicationControlSource source, Result rc=0; TransferMemory tmem={0}; + Service srv={0}; rc = tmemCreateFromMemory(&tmem, buffer, size, Perm_R); - if (R_SUCCEEDED(rc)) rc = _nsListApplicationTitleIcon(a, source, application_ids, count, &tmem, 407); + + if (R_SUCCEEDED(rc)) { + rc = nsGetApplicationManagerInterface(&srv); + if (R_SUCCEEDED(rc)) { + rc = _nsListApplicationTitleIcon(&srv, a, source, application_ids, count, &tmem, 407); + serviceClose(&srv); + } + } tmemClose(&tmem); return rc; } +Result nsListApplicationTitle2(AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, void* buffer, size_t size) { + if (hosversionBefore(20,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + TransferMemory tmem={0}; + Service srv={0}; + + rc = tmemCreateFromMemory(&tmem, buffer, size, Perm_R); + + if (R_SUCCEEDED(rc)) { + rc = nsGetReadOnlyApplicationControlDataInterface(&srv); + if (R_SUCCEEDED(rc)) { + rc = _nsListApplicationTitleIcon(&srv, a, source, application_ids, count, &tmem, 10); + serviceClose(&srv); + } + } + + tmemClose(&tmem); + + return rc; +} + +Result nsListApplicationTitle3(AsyncValue *a, const u64 *application_ids, s32 count, void* buffer, size_t size) { + if (hosversionBefore(20,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + TransferMemory tmem={0}; + Service srv={0}; + + rc = tmemCreateFromMemory(&tmem, buffer, size, Perm_R); + + if (R_SUCCEEDED(rc)) { + rc = nsGetReadOnlyApplicationControlDataInterface(&srv); + if (R_SUCCEEDED(rc)) { + rc = _nsListApplicationTitleIcon2(&srv, a, application_ids, count, &tmem, 13); + serviceClose(&srv); + } + } + + tmemClose(&tmem); + + return rc; +} + Result nsListApplicationIcon(AsyncValue *a, NsApplicationControlSource source, const u64 *application_ids, s32 count, void* buffer, size_t size) { if (hosversionBefore(8,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); Result rc=0; TransferMemory tmem={0}; + Service srv={0}; rc = tmemCreateFromMemory(&tmem, buffer, size, Perm_R); - if (R_SUCCEEDED(rc)) rc = _nsListApplicationTitleIcon(a, source, application_ids, count, &tmem, 408); + if (R_SUCCEEDED(rc)) { + rc = nsGetApplicationManagerInterface(&srv); + if (R_SUCCEEDED(rc)) { + rc = _nsListApplicationTitleIcon(&srv, a, source, application_ids, count, &tmem, 408); + serviceClose(&srv); + } + } tmemClose(&tmem); return rc;