From d1de6b88640e37e52bac098ecb25524cb8720c16 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 6 Nov 2017 16:16:07 -0500
Subject: [PATCH] HLE/APT: Try to launch a native applet in
 PrepareToStartLibraryApplet and PreloadLibraryApplet before falling back to
 HLE applets.

With this commit, you can run native applets if they are in the correct folder of your virtual NAND.

Trying to exit the applet will currently cause an invalid read loop due to svcExitProcess not being implemented.
---
 src/core/hle/service/apt/apt.cpp | 39 ++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 668ef6037..5f2ad6423 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -21,6 +21,7 @@
 #include "core/hle/service/apt/bcfnt/bcfnt.h"
 #include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/fs/archive.h"
+#include "core/hle/service/ns/ns.h"
 #include "core/hle/service/ptm/ptm.h"
 #include "core/hle/service/service.h"
 #include "core/hw/aes/ccm.h"
@@ -804,8 +805,29 @@ void PrepareToStartLibraryApplet(Service::Interface* self) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 
-    // TODO(Subv): Launch the requested applet application.
+    // The real APT service returns an error if there's a pending APT parameter when this function
+    // is called.
+    if (next_parameter) {
+        rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
 
+    const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)];
+
+    if (slot.registered) {
+        rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
+
+    auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id));
+    if (process) {
+        rb.Push(RESULT_SUCCESS);
+        return;
+    }
+
+    // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
     auto applet = HLE::Applets::Applet::Get(applet_id);
     if (applet) {
         LOG_WARNING(Service_APT, "applet has already been started id=%08X",
@@ -838,8 +860,21 @@ void PreloadLibraryApplet(Service::Interface* self) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 
-    // TODO(Subv): Launch the requested applet application.
+    const auto& slot = applet_slots[static_cast<size_t>(AppletSlot::LibraryApplet)];
 
+    if (slot.registered) {
+        rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
+
+    auto process = NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id));
+    if (process) {
+        rb.Push(RESULT_SUCCESS);
+        return;
+    }
+
+    // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
     auto applet = HLE::Applets::Applet::Get(applet_id);
     if (applet) {
         LOG_WARNING(Service_APT, "applet has already been started id=%08X",