diff options
| author | bunnei <bunneidev@gmail.com> | 2019-06-26 15:55:24 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-26 15:55:24 -0400 | 
| commit | 5829ba1ccc18c083a4d2a6e42ad27ebe1c6fbac8 (patch) | |
| tree | 63d9887d2160fe6064f1d2b09b09553c4c8d9fce /src/core/hle | |
| parent | 4ed2774c26602d6ee1af316da5faf391d377d701 (diff) | |
| parent | 3c4238657d326a7d85cbc9152ca16483383c20e7 (diff) | |
Merge pull request #2548 from DarkLordZach/applet-shopn
applets: Implement backend and default frontend for Parental Controls and EShop (ShopN) applets
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_ae.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_ae.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_oe.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_oe.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.cpp | 43 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.h | 14 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/general_backend.cpp | 116 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/general_backend.h | 30 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.cpp | 496 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.h | 37 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 2 | 
13 files changed, 690 insertions, 112 deletions
| diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4a7bf4acb..33cebb48b 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -887,7 +887,9 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {      rb.Push(RESULT_SUCCESS);  } -ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { +ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id) +    : ServiceFramework("ILibraryAppletCreator"), +      current_process_title_id(current_process_title_id) {      static const FunctionInfo functions[] = {          {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},          {1, nullptr, "TerminateAllLibraryApplets"}, @@ -910,7 +912,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)                static_cast<u32>(applet_id), applet_mode);      const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; -    const auto applet = applet_manager.GetApplet(applet_id); +    const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id);      if (applet == nullptr) {          LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); @@ -1234,13 +1236,13 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {  }  void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { +                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {      auto message_queue = std::make_shared<AppletMessageQueue>();      message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on                                                                                        // game boot -    std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); -    std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); +    std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); +    std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);      std::make_shared<IdleSys>()->InstallAsService(service_manager);      std::make_shared<OMM>()->InstallAsService(service_manager);      std::make_shared<SPSM>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 1fa069e56..4ea609d23 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -201,13 +201,15 @@ private:  class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {  public: -    ILibraryAppletCreator(); +    ILibraryAppletCreator(u64 current_process_title_id);      ~ILibraryAppletCreator() override;  private:      void CreateLibraryApplet(Kernel::HLERequestContext& ctx);      void CreateStorage(Kernel::HLERequestContext& ctx);      void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); + +    u64 current_process_title_id;  };  class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { @@ -264,7 +266,7 @@ public:  /// Registers all AM services with the specified service manager.  void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger); +                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);  } // namespace AM  } // namespace Service diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 488add8e7..fe5beb8f9 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -4,6 +4,7 @@  #include "common/logging/log.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applet_ae.h"  #include "core/hle/service/nvflinger/nvflinger.h" @@ -13,9 +14,10 @@ namespace Service::AM {  class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {  public:      explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                                 std::shared_ptr<AppletMessageQueue> msg_queue) +                                 std::shared_ptr<AppletMessageQueue> msg_queue, +                                 Core::System& system)          : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), -          msg_queue(std::move(msg_queue)) { +          msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = {              {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -96,7 +98,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ILibraryAppletCreator>(); +        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());      }      void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -109,14 +111,15 @@ private:      std::shared_ptr<NVFlinger::NVFlinger> nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue; +    Core::System& system;  };  class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {  public:      explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                                std::shared_ptr<AppletMessageQueue> msg_queue) +                                std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)          : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), -          msg_queue(std::move(msg_queue)) { +          msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = {              {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -191,7 +194,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ILibraryAppletCreator>(); +        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());      }      void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { @@ -219,6 +222,7 @@ private:      }      std::shared_ptr<NVFlinger::NVFlinger> nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue; +    Core::System& system;  };  void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { @@ -226,7 +230,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); +    rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);  }  void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { @@ -234,7 +238,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); +    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);  }  void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { @@ -242,13 +246,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); +    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);  }  AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                   std::shared_ptr<AppletMessageQueue> msg_queue) +                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)      : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), -      msg_queue(std::move(msg_queue)) { +      msg_queue(std::move(msg_queue)), system(system) {      // clang-format off      static const FunctionInfo functions[] = {          {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 902db2665..9e006cd9d 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,7 +18,7 @@ namespace AM {  class AppletAE final : public ServiceFramework<AppletAE> {  public:      explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                      std::shared_ptr<AppletMessageQueue> msg_queue); +                      std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);      ~AppletAE() override;      const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; @@ -30,6 +30,7 @@ private:      std::shared_ptr<NVFlinger::NVFlinger> nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue; +    Core::System& system;  };  } // namespace AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index d3a0a1568..6e255fe95 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -4,6 +4,7 @@  #include "common/logging/log.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applet_oe.h"  #include "core/hle/service/nvflinger/nvflinger.h" @@ -13,9 +14,9 @@ namespace Service::AM {  class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {  public:      explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                               std::shared_ptr<AppletMessageQueue> msg_queue) +                               std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)          : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), -          msg_queue(std::move(msg_queue)) { +          msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = {              {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -87,7 +88,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ILibraryAppletCreator>(); +        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());      }      void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -100,6 +101,7 @@ private:      std::shared_ptr<NVFlinger::NVFlinger> nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue; +    Core::System& system;  };  void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { @@ -107,13 +109,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); +    rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);  }  AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                   std::shared_ptr<AppletMessageQueue> msg_queue) +                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)      : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), -      msg_queue(std::move(msg_queue)) { +      msg_queue(std::move(msg_queue)), system(system) {      static const FunctionInfo functions[] = {          {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},      }; diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index bbd0108ef..22c05419d 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,7 +18,7 @@ namespace AM {  class AppletOE final : public ServiceFramework<AppletOE> {  public:      explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                      std::shared_ptr<AppletMessageQueue> msg_queue); +                      std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);      ~AppletOE() override;      const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; @@ -28,6 +28,7 @@ private:      std::shared_ptr<NVFlinger::NVFlinger> nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue; +    Core::System& system;  };  } // namespace AM diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index e3e4ead03..6bdba2468 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -139,12 +139,14 @@ void Applet::Initialize() {  AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, -                                     ProfileSelect profile_select, -                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser) -    : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move( -                                                                          profile_select)}, -      software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {} +AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, +                                     PhotoViewer photo_viewer, ProfileSelect profile_select, +                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser, +                                     ECommerceApplet e_commerce) +    : parental_controls{std::move(parental_controls)}, error{std::move(error)}, +      photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, +      software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, +      e_commerce{std::move(e_commerce)} {}  AppletFrontendSet::~AppletFrontendSet() = default; @@ -157,6 +159,8 @@ AppletManager::AppletManager() = default;  AppletManager::~AppletManager() = default;  void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { +    if (set.parental_controls != nullptr) +        frontend.parental_controls = std::move(set.parental_controls);      if (set.error != nullptr)          frontend.error = std::move(set.error);      if (set.photo_viewer != nullptr) @@ -167,17 +171,21 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {          frontend.software_keyboard = std::move(set.software_keyboard);      if (set.web_browser != nullptr)          frontend.web_browser = std::move(set.web_browser); +    if (set.e_commerce != nullptr) +        frontend.e_commerce = std::move(set.e_commerce);  }  void AppletManager::SetDefaultAppletFrontendSet() { -    frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); -    frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); -    frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); -    frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); -    frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); +    ClearAll(); +    SetDefaultAppletsIfMissing();  }  void AppletManager::SetDefaultAppletsIfMissing() { +    if (frontend.parental_controls == nullptr) { +        frontend.parental_controls = +            std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); +    } +      if (frontend.error == nullptr) {          frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();      } @@ -198,14 +206,20 @@ void AppletManager::SetDefaultAppletsIfMissing() {      if (frontend.web_browser == nullptr) {          frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();      } + +    if (frontend.e_commerce == nullptr) { +        frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); +    }  }  void AppletManager::ClearAll() {      frontend = {};  } -std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { +std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const {      switch (id) { +    case AppletId::Auth: +        return std::make_shared<Auth>(*frontend.parental_controls);      case AppletId::Error:          return std::make_shared<Error>(*frontend.error);      case AppletId::ProfileSelect: @@ -214,8 +228,11 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {          return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);      case AppletId::PhotoViewer:          return std::make_shared<PhotoViewer>(*frontend.photo_viewer); +    case AppletId::LibAppletShop: +        return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id, +                                            frontend.e_commerce.get());      case AppletId::LibAppletOff: -        return std::make_shared<WebBrowser>(*frontend.web_browser); +        return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id);      default:          UNIMPLEMENTED_MSG(              "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 05ae739ca..adc973dad 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -13,7 +13,9 @@  union ResultCode;  namespace Core::Frontend { +class ECommerceApplet;  class ErrorApplet; +class ParentalControlsApplet;  class PhotoViewerApplet;  class ProfileSelectApplet;  class SoftwareKeyboardApplet; @@ -145,15 +147,19 @@ protected:  };  struct AppletFrontendSet { +    using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;      using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;      using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;      using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;      using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;      using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; +    using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;      AppletFrontendSet(); -    AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select, -                      SoftwareKeyboard software_keyboard, WebBrowser web_browser); +    AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, +                      PhotoViewer photo_viewer, ProfileSelect profile_select, +                      SoftwareKeyboard software_keyboard, WebBrowser web_browser, +                      ECommerceApplet e_commerce);      ~AppletFrontendSet();      AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -162,11 +168,13 @@ struct AppletFrontendSet {      AppletFrontendSet(AppletFrontendSet&&) noexcept;      AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; +    ParentalControlsApplet parental_controls;      ErrorApplet error;      PhotoViewer photo_viewer;      ProfileSelect profile_select;      SoftwareKeyboard software_keyboard;      WebBrowser web_browser; +    ECommerceApplet e_commerce;  };  class AppletManager { @@ -179,7 +187,7 @@ public:      void SetDefaultAppletsIfMissing();      void ClearAll(); -    std::shared_ptr<Applet> GetApplet(AppletId id) const; +    std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const;  private:      AppletFrontendSet frontend; diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 54c155dd8..e0def8dff 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -17,6 +17,8 @@  namespace Service::AM::Applets { +constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; +  static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {      std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();      for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { @@ -35,6 +37,120 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)      }  } +Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {} + +Auth::~Auth() = default; + +void Auth::Initialize() { +    Applet::Initialize(); +    complete = false; + +    const auto storage = broker.PopNormalDataToApplet(); +    ASSERT(storage != nullptr); +    const auto data = storage->GetData(); +    ASSERT(data.size() >= 0xC); + +    struct Arg { +        INSERT_PADDING_BYTES(4); +        AuthAppletType type; +        u8 arg0; +        u8 arg1; +        u8 arg2; +        INSERT_PADDING_BYTES(1); +    }; +    static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size."); + +    Arg arg{}; +    std::memcpy(&arg, data.data(), sizeof(Arg)); + +    type = arg.type; +    arg0 = arg.arg0; +    arg1 = arg.arg1; +    arg2 = arg.arg2; +} + +bool Auth::TransactionComplete() const { +    return complete; +} + +ResultCode Auth::GetStatus() const { +    return successful ? RESULT_SUCCESS : ERROR_INVALID_PIN; +} + +void Auth::ExecuteInteractive() { +    UNREACHABLE_MSG("Unexpected interactive applet data."); +} + +void Auth::Execute() { +    if (complete) { +        return; +    } + +    const auto unimplemented_log = [this] { +        UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " +                          "arg1={:02X}, arg2={:02X}", +                          static_cast<u32>(type), arg0, arg1, arg2); +    }; + +    switch (type) { +    case AuthAppletType::ShowParentalAuthentication: { +        const auto callback = [this](bool successful) { AuthFinished(successful); }; + +        if (arg0 == 1 && arg1 == 0 && arg2 == 1) { +            // ShowAuthenticatorForConfiguration +            frontend.VerifyPINForSettings(callback); +        } else if (arg1 == 0 && arg2 == 0) { +            // ShowParentalAuthentication(bool) +            frontend.VerifyPIN(callback, static_cast<bool>(arg0)); +        } else { +            unimplemented_log(); +        } +        break; +    } +    case AuthAppletType::RegisterParentalPasscode: { +        const auto callback = [this] { AuthFinished(true); }; + +        if (arg0 == 0 && arg1 == 0 && arg2 == 0) { +            // RegisterParentalPasscode +            frontend.RegisterPIN(callback); +        } else { +            unimplemented_log(); +        } +        break; +    } +    case AuthAppletType::ChangeParentalPasscode: { +        const auto callback = [this] { AuthFinished(true); }; + +        if (arg0 == 0 && arg1 == 0 && arg2 == 0) { +            // ChangeParentalPasscode +            frontend.ChangePIN(callback); +        } else { +            unimplemented_log(); +        } +        break; +    } +    default: +        unimplemented_log(); +    } +} + +void Auth::AuthFinished(bool successful) { +    this->successful = successful; + +    struct Return { +        ResultCode result_code; +    }; +    static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size."); + +    Return return_{GetStatus()}; + +    std::vector<u8> out(sizeof(Return)); +    std::memcpy(out.data(), &return_, sizeof(Return)); + +    broker.PushNormalDataFromApplet(IStorage{out}); +    broker.SignalStateChanged(); +} +  PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}  PhotoViewer::~PhotoViewer() = default; diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index fb68a2543..0da252044 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h @@ -8,6 +8,36 @@  namespace Service::AM::Applets { +enum class AuthAppletType : u32 { +    ShowParentalAuthentication, +    RegisterParentalPasscode, +    ChangeParentalPasscode, +}; + +class Auth final : public Applet { +public: +    explicit Auth(Core::Frontend::ParentalControlsApplet& frontend); +    ~Auth() override; + +    void Initialize() override; +    bool TransactionComplete() const override; +    ResultCode GetStatus() const override; +    void ExecuteInteractive() override; +    void Execute() override; + +    void AuthFinished(bool successful = true); + +private: +    Core::Frontend::ParentalControlsApplet& frontend; +    bool complete = false; +    bool successful = false; + +    AuthAppletType type = AuthAppletType::ShowParentalAuthentication; +    u8 arg0 = 0; +    u8 arg1 = 0; +    u8 arg2 = 0; +}; +  enum class PhotoViewerAppletMode : u8 {      CurrentApp = 0,      AllApps = 1, diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7878f5136..2762e0653 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -19,7 +19,9 @@  #include "core/file_sys/nca_metadata.h"  #include "core/file_sys/registered_cache.h"  #include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h"  #include "core/file_sys/vfs_types.h" +#include "core/frontend/applets/general_frontend.h"  #include "core/frontend/applets/web_browser.h"  #include "core/hle/kernel/process.h"  #include "core/hle/service/am/applets/web_browser.h" @@ -28,74 +30,187 @@  namespace Service::AM::Applets { -// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not -// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, -// but some may be worth an implementation. -constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; +enum class WebArgTLVType : u16 { +    InitialURL = 0x1, +    ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name. +    CallbackURL = 0x3, +    CallbackableURL = 0x4, +    ApplicationID = 0x5, +    DocumentPath = 0x6, +    DocumentKind = 0x7, +    SystemDataID = 0x8, +    ShareStartPage = 0x9, +    Whitelist = 0xA, +    News = 0xB, +    UserID = 0xE, +    AlbumEntry0 = 0xF, +    ScreenShotEnabled = 0x10, +    EcClientCertEnabled = 0x11, +    Unk12 = 0x12, +    PlayReportEnabled = 0x13, +    Unk14 = 0x14, +    Unk15 = 0x15, +    BootDisplayKind = 0x17, +    BackgroundKind = 0x18, +    FooterEnabled = 0x19, +    PointerEnabled = 0x1A, +    LeftStickMode = 0x1B, +    KeyRepeatFrame1 = 0x1C, +    KeyRepeatFrame2 = 0x1D, +    BootAsMediaPlayerInv = 0x1E, +    DisplayUrlKind = 0x1F, +    BootAsMediaPlayer = 0x21, +    ShopJumpEnabled = 0x22, +    MediaAutoPlayEnabled = 0x23, +    LobbyParameter = 0x24, +    ApplicationAlbumEntry = 0x26, +    JsExtensionEnabled = 0x27, +    AdditionalCommentText = 0x28, +    TouchEnabledOnContents = 0x29, +    UserAgentAdditionalString = 0x2A, +    AdditionalMediaData0 = 0x2B, +    MediaPlayerAutoCloseEnabled = 0x2C, +    PageCacheEnabled = 0x2D, +    WebAudioEnabled = 0x2E, +    Unk2F = 0x2F, +    YouTubeVideoWhitelist = 0x31, +    FooterFixedKind = 0x32, +    PageFadeEnabled = 0x33, +    MediaCreatorApplicationRatingAge = 0x34, +    BootLoadingIconEnabled = 0x35, +    PageScrollIndicationEnabled = 0x36, +    MediaPlayerSpeedControlEnabled = 0x37, +    AlbumEntry1 = 0x38, +    AlbumEntry2 = 0x39, +    AlbumEntry3 = 0x3A, +    AdditionalMediaData1 = 0x3B, +    AdditionalMediaData2 = 0x3C, +    AdditionalMediaData3 = 0x3D, +    BootFooterButton = 0x3E, +    OverrideWebAudioVolume = 0x3F, +    OverrideMediaAudioVolume = 0x40, +    BootMode = 0x41, +    WebSessionEnabled = 0x42, +}; + +enum class ShimKind : u32 { +    Shop = 1, +    Login = 2, +    Offline = 3, +    Share = 4, +    Web = 5, +    Wifi = 6, +    Lobby = 7, +}; + +enum class ShopWebTarget { +    ApplicationInfo, +    AddOnContentList, +    SubscriptionList, +    ConsumableItemList, +    Home, +    Settings, +}; + +namespace { -struct WebBufferHeader { +constexpr std::size_t SHIM_KIND_COUNT = 0x8; + +struct WebArgHeader {      u16 count; -    INSERT_PADDING_BYTES(6); +    INSERT_PADDING_BYTES(2); +    ShimKind kind;  }; -static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); +static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); -struct WebArgumentHeader { -    u16 type; +struct WebArgTLV { +    WebArgTLVType type;      u16 size;      u32 offset;  }; -static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); +static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size."); -struct WebArgumentResult { +struct WebCommonReturnValue {      u32 result_code; +    INSERT_PADDING_BYTES(0x4);      std::array<char, 0x1000> last_url;      u64 last_url_size;  }; -static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); - -static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { -    WebBufferHeader header; -    ASSERT(sizeof(WebBufferHeader) <= data.size()); -    std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); - -    u64 offset = sizeof(WebBufferHeader); -    for (u16 i = 0; i < header.count; ++i) { -        WebArgumentHeader arg; -        ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); -        std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); -        offset += sizeof(WebArgumentHeader); - -        if (arg.type == type) { -            std::vector<u8> out(arg.size); -            offset += arg.offset; -            ASSERT(offset + arg.size <= data.size()); -            std::memcpy(out.data(), data.data() + offset, out.size()); +static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); + +struct WebWifiPageArg { +    INSERT_PADDING_BYTES(4); +    std::array<char, 0x100> connection_test_url; +    std::array<char, 0x400> initial_url; +    std::array<u8, 0x10> nifm_network_uuid; +    u32 nifm_requirement; +}; +static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size."); + +struct WebWifiReturnValue { +    INSERT_PADDING_BYTES(4); +    u32 result; +}; +static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size."); + +enum class OfflineWebSource : u32 { +    OfflineHtmlPage = 0x1, +    ApplicationLegalInformation = 0x2, +    SystemDataPage = 0x3, +}; + +std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) { +    if (arg.size() < sizeof(WebArgHeader)) +        return {}; + +    WebArgHeader header{}; +    std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); + +    std::map<WebArgTLVType, std::vector<u8>> out; +    u64 offset = sizeof(WebArgHeader); +    for (std::size_t i = 0; i < header.count; ++i) { +        if (arg.size() < (offset + sizeof(WebArgTLV)))              return out; -        } -        offset += arg.offset + arg.size; -    } +        WebArgTLV tlv{}; +        std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); +        offset += sizeof(WebArgTLV); -    return {}; -} +        offset += tlv.offset; +        if (arg.size() < (offset + tlv.size)) +            return out; + +        std::vector<u8> data(tlv.size); +        std::memcpy(data.data(), arg.data() + offset, tlv.size); +        offset += tlv.size; -static FileSys::VirtualFile GetManualRomFS() { -    auto& loader{Core::System::GetInstance().GetAppLoader()}; +        out.insert_or_assign(tlv.type, data); +    } -    FileSys::VirtualFile out; -    if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) -        return out; +    return out; +} +FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) {      const auto& installed{Core::System::GetInstance().GetContentProvider()}; -    const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), -                                        FileSys::ContentRecordType::Manual); +    const auto res = installed.GetEntry(title_id, type); -    if (res != nullptr) +    if (res != nullptr) {          return res->GetRomFS(); +    } + +    if (type == FileSys::ContentRecordType::Data) { +        return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); +    } +      return nullptr;  } -WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} +} // Anonymous namespace + +WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, +                       Core::Frontend::ECommerceApplet* frontend_e_commerce) +    : frontend(frontend), frontend_e_commerce(frontend_e_commerce), +      current_process_title_id(current_process_title_id) {}  WebBrowser::~WebBrowser() = default; @@ -111,24 +226,12 @@ void WebBrowser::Initialize() {      ASSERT(web_arg_storage != nullptr);      const auto& web_arg = web_arg_storage->GetData(); -    const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); -    filename = Common::StringFromFixedZeroTerminatedBuffer( -        reinterpret_cast<const char*>(url_data.data()), url_data.size()); +    ASSERT(web_arg.size() >= 0x8); +    std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind)); -    temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + -                                               "web_applet_manual", -                                           FileUtil::DirectorySeparator::PlatformDefault); -    FileUtil::DeleteDirRecursively(temporary_dir); +    args = GetWebArguments(web_arg); -    manual_romfs = GetManualRomFS(); -    if (manual_romfs == nullptr) { -        status = ResultCode(-1); -        LOG_ERROR(Service_AM, "Failed to find manual for current process!"); -    } - -    filename = -        FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, -                               FileUtil::DirectorySeparator::PlatformDefault); +    InitializeInternal();  }  bool WebBrowser::TransactionComplete() const { @@ -144,24 +247,25 @@ void WebBrowser::ExecuteInteractive() {  }  void WebBrowser::Execute() { -    if (complete) +    if (complete) {          return; +    }      if (status != RESULT_SUCCESS) {          complete = true;          return;      } -    frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); +    ExecuteInternal();  }  void WebBrowser::UnpackRomFS() {      if (unpacked)          return; -    ASSERT(manual_romfs != nullptr); +    ASSERT(offline_romfs != nullptr);      const auto dir = -        FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); +        FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);      const auto& vfs{Core::System::GetInstance().GetFilesystem()};      const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);      FileSys::VfsRawCopyD(dir, temp_dir); @@ -172,17 +276,275 @@ void WebBrowser::UnpackRomFS() {  void WebBrowser::Finalize() {      complete = true; -    WebArgumentResult out{}; +    WebCommonReturnValue out{};      out.result_code = 0;      out.last_url_size = 0; -    std::vector<u8> data(sizeof(WebArgumentResult)); -    std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); +    std::vector<u8> data(sizeof(WebCommonReturnValue)); +    std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));      broker.PushNormalDataFromApplet(IStorage{data});      broker.SignalStateChanged(); +    if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { +        FileUtil::DeleteDirRecursively(temporary_dir); +    } +} + +void WebBrowser::InitializeInternal() { +    using WebAppletInitializer = void (WebBrowser::*)(); + +    constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{ +        nullptr, &WebBrowser::InitializeShop, +        nullptr, &WebBrowser::InitializeOffline, +        nullptr, nullptr, +        nullptr, nullptr, +    }; + +    const auto index = static_cast<u32>(kind); + +    if (index > functions.size() || functions[index] == nullptr) { +        LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); +        return; +    } + +    const auto function = functions[index]; +    (this->*function)(); +} + +void WebBrowser::ExecuteInternal() { +    using WebAppletExecutor = void (WebBrowser::*)(); + +    constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{ +        nullptr, &WebBrowser::ExecuteShop, +        nullptr, &WebBrowser::ExecuteOffline, +        nullptr, nullptr, +        nullptr, nullptr, +    }; + +    const auto index = static_cast<u32>(kind); + +    if (index > functions.size() || functions[index] == nullptr) { +        LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); +        return; +    } + +    const auto function = functions[index]; +    (this->*function)(); +} + +void WebBrowser::InitializeShop() { +    if (frontend_e_commerce == nullptr) { +        LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!"); +        status = ResultCode(-1); +        return; +    } + +    const auto user_id_data = args.find(WebArgTLVType::UserID); + +    user_id = std::nullopt; +    if (user_id_data != args.end()) { +        user_id = u128{}; +        std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128)); +    } + +    const auto url = args.find(WebArgTLVType::ShopArgumentsURL); + +    if (url == args.end()) { +        LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); +        status = ResultCode(-1); +        return; +    } + +    std::vector<std::string> split_query; +    Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer( +                            reinterpret_cast<const char*>(url->second.data()), url->second.size()), +                        '?', split_query); + +    // 2 -> Main URL '?' Query Parameters +    // Less is missing info, More is malformed +    if (split_query.size() != 2) { +        LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed"); +        status = ResultCode(-1); +        return; +    } + +    std::vector<std::string> queries; +    Common::SplitString(split_query[1], '&', queries); + +    const auto split_single_query = +        [](const std::string& in) -> std::pair<std::string, std::string> { +        const auto index = in.find('='); +        if (index == std::string::npos || index == in.size() - 1) { +            return {in, ""}; +        } + +        return {in.substr(0, index), in.substr(index + 1)}; +    }; + +    std::transform(queries.begin(), queries.end(), +                   std::inserter(shop_query, std::next(shop_query.begin())), split_single_query); + +    const auto scene = shop_query.find("scene"); + +    if (scene == shop_query.end()) { +        LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); +        status = ResultCode(-1); +        return; +    } + +    const std::map<std::string, ShopWebTarget, std::less<>> target_map{ +        {"product_detail", ShopWebTarget::ApplicationInfo}, +        {"aocs", ShopWebTarget::AddOnContentList}, +        {"subscriptions", ShopWebTarget::SubscriptionList}, +        {"consumption", ShopWebTarget::ConsumableItemList}, +        {"settings", ShopWebTarget::Settings}, +        {"top", ShopWebTarget::Home}, +    }; + +    const auto target = target_map.find(scene->second); +    if (target == target_map.end()) { +        LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); +        status = ResultCode(-1); +        return; +    } + +    shop_web_target = target->second; + +    const auto title_id_data = shop_query.find("dst_app_id"); +    if (title_id_data != shop_query.end()) { +        title_id = std::stoull(title_id_data->second, nullptr, 0x10); +    } + +    const auto mode_data = shop_query.find("mode"); +    if (mode_data != shop_query.end()) { +        shop_full_display = mode_data->second == "full"; +    } +} + +void WebBrowser::InitializeOffline() { +    if (args.find(WebArgTLVType::DocumentPath) == args.end() || +        args.find(WebArgTLVType::DocumentKind) == args.end() || +        args.find(WebArgTLVType::ApplicationID) == args.end()) { +        status = ResultCode(-1); +        LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!"); +    } + +    const auto url_data = args[WebArgTLVType::DocumentPath]; +    filename = Common::StringFromFixedZeroTerminatedBuffer( +        reinterpret_cast<const char*>(url_data.data()), url_data.size()); + +    OfflineWebSource source; +    ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4); +    std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource)); + +    constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{ +        "manual", +        "legal", +        "system", +    }; + +    temporary_dir = +        FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" + +                                   WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], +                               FileUtil::DirectorySeparator::PlatformDefault);      FileUtil::DeleteDirRecursively(temporary_dir); + +    u64 title_id = 0; // 0 corresponds to current process +    ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8); +    std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64)); +    FileSys::ContentRecordType type = FileSys::ContentRecordType::Data; + +    switch (source) { +    case OfflineWebSource::OfflineHtmlPage: +        // While there is an AppID TLV field, in official SW this is always ignored. +        title_id = 0; +        type = FileSys::ContentRecordType::Manual; +        break; +    case OfflineWebSource::ApplicationLegalInformation: +        type = FileSys::ContentRecordType::Legal; +        break; +    case OfflineWebSource::SystemDataPage: +        type = FileSys::ContentRecordType::Data; +        break; +    } + +    if (title_id == 0) { +        title_id = current_process_title_id; +    } + +    offline_romfs = GetApplicationRomFS(title_id, type); +    if (offline_romfs == nullptr) { +        status = ResultCode(-1); +        LOG_ERROR(Service_AM, "Failed to find offline data for request!"); +    } + +    std::string path_additional_directory; +    if (source == OfflineWebSource::OfflineHtmlPage) { +        path_additional_directory = std::string(DIR_SEP).append("html-document"); +    } + +    filename = +        FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, +                               FileUtil::DirectorySeparator::PlatformDefault); +} + +void WebBrowser::ExecuteShop() { +    const auto callback = [this]() { Finalize(); }; + +    const auto check_optional_parameter = [this](const auto& p) { +        if (!p.has_value()) { +            LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); +            status = ResultCode(-1); +            return false; +        } + +        return true; +    }; + +    switch (shop_web_target) { +    case ShopWebTarget::ApplicationInfo: +        if (!check_optional_parameter(title_id)) +            return; +        frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id, +                                                        shop_full_display, shop_extra_parameter); +        break; +    case ShopWebTarget::AddOnContentList: +        if (!check_optional_parameter(title_id)) +            return; +        frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display); +        break; +    case ShopWebTarget::ConsumableItemList: +        if (!check_optional_parameter(title_id)) +            return; +        frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id); +        break; +    case ShopWebTarget::Home: +        if (!check_optional_parameter(user_id)) +            return; +        if (!check_optional_parameter(shop_full_display)) +            return; +        frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display); +        break; +    case ShopWebTarget::Settings: +        if (!check_optional_parameter(user_id)) +            return; +        if (!check_optional_parameter(shop_full_display)) +            return; +        frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display); +        break; +    case ShopWebTarget::SubscriptionList: +        if (!check_optional_parameter(title_id)) +            return; +        frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id); +        break; +    default: +        UNREACHABLE(); +    } +} + +void WebBrowser::ExecuteOffline() { +    frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });  }  } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 7e0f34c7d..870f57b64 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -4,15 +4,22 @@  #pragma once +#include <map>  #include "core/file_sys/vfs_types.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applets/applets.h"  namespace Service::AM::Applets { +enum class ShimKind : u32; +enum class ShopWebTarget; +enum class WebArgTLVType : u16; +  class WebBrowser final : public Applet {  public: -    WebBrowser(Core::Frontend::WebBrowserApplet& frontend); +    WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, +               Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr); +      ~WebBrowser() override;      void Initialize() override; @@ -32,15 +39,41 @@ public:      void Finalize();  private: +    void InitializeInternal(); +    void ExecuteInternal(); + +    // Specific initializers for the types of web applets +    void InitializeShop(); +    void InitializeOffline(); + +    // Specific executors for the types of web applets +    void ExecuteShop(); +    void ExecuteOffline(); +      Core::Frontend::WebBrowserApplet& frontend; +    // Extra frontends for specialized functions +    Core::Frontend::ECommerceApplet* frontend_e_commerce; +      bool complete = false;      bool unpacked = false;      ResultCode status = RESULT_SUCCESS; -    FileSys::VirtualFile manual_romfs; +    u64 current_process_title_id; + +    ShimKind kind; +    std::map<WebArgTLVType, std::vector<u8>> args; + +    FileSys::VirtualFile offline_romfs;      std::string temporary_dir;      std::string filename; + +    ShopWebTarget shop_web_target; +    std::map<std::string, std::string, std::less<>> shop_query; +    std::optional<u64> title_id = 0; +    std::optional<u128> user_id; +    std::optional<bool> shop_full_display; +    std::string shop_extra_parameter;  };  } // namespace Service::AM::Applets diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index beae9c510..ec9d755b7 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -204,7 +204,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,      SM::ServiceManager::InstallInterfaces(sm);      Account::InstallInterfaces(system); -    AM::InstallInterfaces(*sm, nv_flinger); +    AM::InstallInterfaces(*sm, nv_flinger, system);      AOC::InstallInterfaces(*sm);      APM::InstallInterfaces(*sm);      Audio::InstallInterfaces(*sm); | 
