From 29dd63e5db4c61a3e9a1013feb936629c6605070 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Thu, 11 Jun 2020 19:00:07 -0400 Subject: [PATCH] Added support for nifmLa. Added nifmRequestGetAppletInfo. --- nx/include/switch.h | 1 + nx/include/switch/applets/nifm_la.h | 16 +++++ nx/include/switch/services/nifm.h | 13 ++++ nx/source/applets/nifm_la.c | 93 +++++++++++++++++++++++++++++ nx/source/services/nifm.c | 23 +++++++ 5 files changed, 146 insertions(+) create mode 100644 nx/include/switch/applets/nifm_la.h create mode 100644 nx/source/applets/nifm_la.c diff --git a/nx/include/switch.h b/nx/include/switch.h index ecbb0d71..2549f45b 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -137,6 +137,7 @@ extern "C" { #include "switch/applets/hid_la.h" #include "switch/applets/mii_la.h" #include "switch/applets/nfp_la.h" +#include "switch/applets/nifm_la.h" #include "switch/applets/pctlauth.h" #include "switch/applets/psel.h" #include "switch/applets/error.h" diff --git a/nx/include/switch/applets/nifm_la.h b/nx/include/switch/applets/nifm_la.h new file mode 100644 index 00000000..5bcf27a4 --- /dev/null +++ b/nx/include/switch/applets/nifm_la.h @@ -0,0 +1,16 @@ +/** + * @file nifm_la.h + * @brief Wrapper for using the nifm LibraryApplet (the launched applet varies). + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/nifm.h" + +/** + * @brief Uses \ref nifmGetResult, then on failure launches the applet. + * @param r \ref NifmRequest + */ +Result nifmLaHandleNetworkRequestResult(NifmRequest* r); + diff --git a/nx/include/switch/services/nifm.h b/nx/include/switch/services/nifm.h index f1b67d31..fed33cd7 100644 --- a/nx/include/switch/services/nifm.h +++ b/nx/include/switch/services/nifm.h @@ -269,5 +269,18 @@ Result nifmRequestSubmit(NifmRequest* r); */ Result nifmRequestSubmitAndWait(NifmRequest* r); +/** + * @brief GetAppletInfo + * @note This is used by \ref nifmLaHandleNetworkRequestResult. + * @param r \ref NifmRequest + * @param[in] theme_color ThemeColor + * @param[out] buffer Output buffer for storage data. + * @param[in] size Output buffer size. + * @param[out] applet_id \ref AppletId + * @param[out] mode \ref LibAppletMode + * @param[out] out_size Total data size written to the output buffer. + */ +Result nifmRequestGetAppletInfo(NifmRequest* r, u32 theme_color, void* buffer, size_t size, u32 *applet_id, u32 *mode, u32 *out_size); + ///@} diff --git a/nx/source/applets/nifm_la.c b/nx/source/applets/nifm_la.c new file mode 100644 index 00000000..91e00f21 --- /dev/null +++ b/nx/source/applets/nifm_la.c @@ -0,0 +1,93 @@ +#include +#include "libapplet_internal.h" +#include "applets/nifm_la.h" + +static Result _nifmLaPrepare(NifmRequest* r, AppletHolder *holder) { + Result rc=0; + u32 applet_id=0; + u32 mode=0; + u32 out_size=0; + u8 buf[0x1000]; + u8 *data_ptr = buf; + + memset(buf, 0, sizeof(buf)); + rc = nifmRequestGetAppletInfo(r, appletGetThemeColorType(), buf, sizeof(buf), &applet_id, &mode, &out_size); + if (R_FAILED(rc)) return rc; + + rc = appletCreateLibraryApplet(holder, applet_id, mode); + if (R_FAILED(rc)) return rc; + + while(out_size >= sizeof(s32)) { + s32 storage_size = *((s32*)data_ptr); + data_ptr+= sizeof(s32); + out_size-= sizeof(s32); + if (storage_size == -1) return 0; + + if (out_size <= storage_size) break; + + rc = libappletPushInData(holder, data_ptr, storage_size); + if (R_FAILED(rc)) return rc; + + data_ptr+= storage_size; + out_size-= storage_size; + } + return MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen); +} + +static Result _nifmLaFinish(AppletHolder *holder) { + Result rc=0; + AppletStorage storage; + s64 storage_size=0; + + appletHolderJoin(holder); + + LibAppletExitReason reason = appletHolderGetExitReason(holder); + + if (reason == LibAppletExitReason_Canceled || reason == LibAppletExitReason_Abnormal || reason == LibAppletExitReason_Unexpected) { + rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); + } + + if (R_SUCCEEDED(rc)) rc = appletHolderPopOutData(holder, &storage); + + if (R_SUCCEEDED(rc)) rc = appletStorageGetSize(&storage, &storage_size); + + if (R_SUCCEEDED(rc)) { + s32 ret=-1; + if (storage_size == sizeof(ret)) { + rc = appletStorageRead(&storage, 0, &ret, sizeof(ret)); + if (R_SUCCEEDED(rc)) rc = ret==0 ? MAKERESULT(110, 190) : MAKERESULT(110, 2900); + } + else if (storage_size >= sizeof(ret)) { + storage_size-= sizeof(ret); + Result tmprc=0; + rc = appletStorageRead(&storage, 0, &ret, sizeof(ret)); + if (R_SUCCEEDED(rc)) rc = appletStorageRead(&storage, sizeof(ret), &tmprc, storage_size < sizeof(tmprc) ? storage_size : sizeof(tmprc)); + if (R_SUCCEEDED(rc)) { + if ((!ret && storage_size != sizeof(tmprc)) || (ret && storage_size < sizeof(tmprc))) + rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); + } + if (R_SUCCEEDED(rc)) rc = tmprc; + } + else + rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); + appletStorageClose(&storage); + } + + return rc; +} + +Result nifmLaHandleNetworkRequestResult(NifmRequest* r) { + Result rc=0; + AppletHolder holder={0}; + + rc = nifmGetResult(r); + if (R_SUCCEEDED(rc)) return rc; + + rc = _nifmLaPrepare(r, &holder); + if (R_SUCCEEDED(rc)) rc = appletHolderStart(&holder); + if (R_SUCCEEDED(rc)) rc = _nifmLaFinish(&holder); + + appletHolderClose(&holder); + return rc; +} + diff --git a/nx/source/services/nifm.c b/nx/source/services/nifm.c index 8756de5b..ba5ec484 100644 --- a/nx/source/services/nifm.c +++ b/nx/source/services/nifm.c @@ -429,3 +429,26 @@ Result nifmRequestSubmitAndWait(NifmRequest* r) { return rc; } +Result nifmRequestGetAppletInfo(NifmRequest* r, u32 theme_color, void* buffer, size_t size, u32 *applet_id, u32 *mode, u32 *out_size) { + if (!serviceIsActive(&r->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + struct { + u32 applet_id; + u32 mode; + u32 out_size; + } out; + + serviceAssumeDomain(&r->s); + Result rc = serviceDispatchInOut(&r->s, 21, theme_color, out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { buffer, size } }, + ); + if (R_SUCCEEDED(rc)) { + if (applet_id) *applet_id = out.applet_id; + if (mode) *mode = out.mode; + if (out_size) *out_size = out.out_size; + } + return rc; +} +