Skip to content
14 changes: 14 additions & 0 deletions nx/include/switch/services/ns.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,20 @@ 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) + sizeof(\ref NsApplicationControlData).
*/
Result nsListApplicationTitle2(AsyncValue *a, NsApplicationControlSource source, 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.
Expand Down
50 changes: 42 additions & 8 deletions nx/source/services/ns.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -992,7 +989,7 @@ 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,
Expand All @@ -1006,7 +1003,6 @@ static Result _nsListApplicationTitleIcon(AsyncValue *a, NsApplicationControlSou
if (R_SUCCEEDED(rc))
eventLoadRemote(&a->event, event, false);

serviceClose(&srv);
return rc;
}

Expand All @@ -1016,23 +1012,61 @@ 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 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;
Expand Down