summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp227
-rw-r--r--src/core/hle/service/am/applets/web_browser.h25
-rw-r--r--src/core/hle/service/am/applets/web_types.h178
3 files changed, 428 insertions, 2 deletions
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 74ef037fe..7f398254e 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <optional>
+
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/result.h"
@@ -12,6 +15,76 @@
namespace Service::AM::Applets {
+namespace {
+
+template <typename T>
+void ParseRawValue(T& value, const std::vector<u8>& data) {
+ static_assert(std::is_trivially_copyable_v<T>,
+ "It's undefined behavior to use memcpy with non-trivially copyable objects");
+ std::memcpy(&value, data.data(), data.size());
+}
+
+template <typename T>
+T ParseRawValue(const std::vector<u8>& data) {
+ T value;
+ ParseRawValue(value, data);
+ return value;
+}
+
+std::string ParseStringValue(const std::vector<u8>& data) {
+ return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast<const char*>(data.data()),
+ data.size());
+}
+
+WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
+ std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
+
+ if (web_arg.size() == sizeof(WebArgHeader)) {
+ return {};
+ }
+
+ WebArgInputTLVMap input_tlv_map;
+
+ u64 current_offset = sizeof(WebArgHeader);
+
+ for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
+ if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
+ return input_tlv_map;
+ }
+
+ WebArgInputTLV input_tlv;
+ std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
+
+ current_offset += sizeof(WebArgInputTLV);
+
+ if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
+ return input_tlv_map;
+ }
+
+ std::vector<u8> data(input_tlv.arg_data_size);
+ std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
+
+ current_offset += input_tlv.arg_data_size;
+
+ input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
+ }
+
+ return input_tlv_map;
+}
+
+std::optional<std::vector<u8>> GetInputTLVData(const WebArgInputTLVMap& input_tlv_map,
+ WebArgInputTLVType input_tlv_type) {
+ const auto map_it = input_tlv_map.find(input_tlv_type);
+
+ if (map_it == input_tlv_map.end()) {
+ return std::nullopt;
+ }
+
+ return map_it->second;
+}
+
+} // namespace
+
WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
@@ -19,6 +92,55 @@ WebBrowser::~WebBrowser() = default;
void WebBrowser::Initialize() {
Applet::Initialize();
+
+ LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
+
+ LOG_DEBUG(Service_AM,
+ "Initializing Applet with common_args: arg_version={}, lib_version={}, "
+ "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
+ common_args.arguments_version, common_args.library_version,
+ common_args.play_startup_sound, common_args.size, common_args.system_tick,
+ common_args.theme_color);
+
+ web_applet_version = WebAppletVersion{common_args.library_version};
+
+ const auto web_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(web_arg_storage != nullptr);
+
+ const auto& web_arg = web_arg_storage->GetData();
+ ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; });
+
+ web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header);
+
+ LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}",
+ web_arg_header.total_tlv_entries, web_arg_header.shim_kind);
+
+ switch (web_arg_header.shim_kind) {
+ case ShimKind::Shop:
+ InitializeShop();
+ break;
+ case ShimKind::Login:
+ InitializeLogin();
+ break;
+ case ShimKind::Offline:
+ InitializeOffline();
+ break;
+ case ShimKind::Share:
+ InitializeShare();
+ break;
+ case ShimKind::Web:
+ InitializeWeb();
+ break;
+ case ShimKind::Wifi:
+ InitializeWifi();
+ break;
+ case ShimKind::Lobby:
+ InitializeLobby();
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
+ break;
+ }
}
bool WebBrowser::TransactionComplete() const {
@@ -30,9 +152,110 @@ ResultCode WebBrowser::GetStatus() const {
}
void WebBrowser::ExecuteInteractive() {
- UNIMPLEMENTED_MSG("Unexpected interactive data recieved!");
+ UNIMPLEMENTED_MSG("WebSession is not implemented");
+}
+
+void WebBrowser::Execute() {
+ switch (web_arg_header.shim_kind) {
+ case ShimKind::Shop:
+ ExecuteShop();
+ break;
+ case ShimKind::Login:
+ ExecuteLogin();
+ break;
+ case ShimKind::Offline:
+ ExecuteOffline();
+ break;
+ case ShimKind::Share:
+ ExecuteShare();
+ break;
+ case ShimKind::Web:
+ ExecuteWeb();
+ break;
+ case ShimKind::Wifi:
+ ExecuteWifi();
+ break;
+ case ShimKind::Lobby:
+ ExecuteLobby();
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+ break;
+ }
+}
+
+void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) {
+ if ((web_arg_header.shim_kind == ShimKind::Share &&
+ web_applet_version >= WebAppletVersion::Version196608) ||
+ (web_arg_header.shim_kind == ShimKind::Web &&
+ web_applet_version >= WebAppletVersion::Version524288)) {
+ // TODO: Push Output TLVs instead of a WebCommonReturnValue
+ }
+
+ WebCommonReturnValue web_common_return_value;
+
+ web_common_return_value.exit_reason = exit_reason;
+ std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size());
+ web_common_return_value.last_url_size = last_url.size();
+
+ LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}",
+ exit_reason, last_url, last_url.size());
+
+ complete = true;
+ std::vector<u8> out_data(sizeof(WebCommonReturnValue));
+ std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+ broker.SignalStateChanged();
}
-void WebBrowser::Execute() {}
+void WebBrowser::InitializeShop() {}
+
+void WebBrowser::InitializeLogin() {}
+
+void WebBrowser::InitializeOffline() {}
+
+void WebBrowser::InitializeShare() {}
+
+void WebBrowser::InitializeWeb() {}
+
+void WebBrowser::InitializeWifi() {}
+
+void WebBrowser::InitializeLobby() {}
+
+void WebBrowser::ExecuteShop() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteLogin() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteOffline() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Offline Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteShare() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteWeb() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Web Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteWifi() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
+
+void WebBrowser::ExecuteLobby() {
+ LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
+ WebBrowserExit(WebExitReason::EndButtonPressed);
+}
} // 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 0584142e5..a1ed5fd1d 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -8,6 +8,7 @@
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/am/applets/web_types.h"
namespace Core {
class System;
@@ -28,12 +29,36 @@ public:
void ExecuteInteractive() override;
void Execute() override;
+ void WebBrowserExit(WebExitReason exit_reason, std::string last_url = "");
+
private:
+ // Initializers for the various types of browser applets
+ void InitializeShop();
+ void InitializeLogin();
+ void InitializeOffline();
+ void InitializeShare();
+ void InitializeWeb();
+ void InitializeWifi();
+ void InitializeLobby();
+
+ // Executors for the various types of browser applets
+ void ExecuteShop();
+ void ExecuteLogin();
+ void ExecuteOffline();
+ void ExecuteShare();
+ void ExecuteWeb();
+ void ExecuteWifi();
+ void ExecuteLobby();
+
const Core::Frontend::WebBrowserApplet& frontend;
bool complete{false};
ResultCode status{RESULT_SUCCESS};
+ WebAppletVersion web_applet_version;
+ WebArgHeader web_arg_header;
+ WebArgInputTLVMap web_arg_input_tlv_map;
+
Core::System& system;
};
diff --git a/src/core/hle/service/am/applets/web_types.h b/src/core/hle/service/am/applets/web_types.h
new file mode 100644
index 000000000..419c2bf79
--- /dev/null
+++ b/src/core/hle/service/am/applets/web_types.h
@@ -0,0 +1,178 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <unordered_map>
+#include <vector>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace Service::AM::Applets {
+
+enum class WebAppletVersion : u32_le {
+ Version0 = 0x0, // Only used by WifiWebAuthApplet
+ Version131072 = 0x20000, // 1.0.0 - 2.3.0
+ Version196608 = 0x30000, // 3.0.0 - 4.1.0
+ Version327680 = 0x50000, // 5.0.0 - 5.1.0
+ Version393216 = 0x60000, // 6.0.0 - 7.0.1
+ Version524288 = 0x80000, // 8.0.0+
+};
+
+enum class ShimKind : u32 {
+ Shop = 1,
+ Login = 2,
+ Offline = 3,
+ Share = 4,
+ Web = 5,
+ Wifi = 6,
+ Lobby = 7,
+};
+
+enum class WebExitReason : u32 {
+ EndButtonPressed = 0,
+ BackButtonPressed = 1,
+ ExitRequested = 2,
+ CallbackURL = 3,
+ WindowClosed = 4,
+ ErrorDialog = 7,
+};
+
+enum class WebArgInputTLVType : u16 {
+ InitialURL = 0x1,
+ 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,
+ PlayReportEnabled = 0x13,
+ BootDisplayKind = 0x17,
+ BackgroundKind = 0x18,
+ FooterEnabled = 0x19,
+ PointerEnabled = 0x1A,
+ LeftStickMode = 0x1B,
+ KeyRepeatFrame1 = 0x1C,
+ KeyRepeatFrame2 = 0x1D,
+ BootAsMediaPlayerInverted = 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,
+ YouTubeVideoWhitelist = 0x31,
+ FooterFixedKind = 0x32,
+ PageFadeEnabled = 0x33,
+ MediaCreatorApplicationRatingAge = 0x34,
+ BootLoadingIconEnabled = 0x35,
+ PageScrollIndicatorEnabled = 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,
+ MediaPlayerOfflineEnabled = 0x43,
+};
+
+enum class WebArgOutputTLVType : u16 {
+ ShareExitReason = 0x1,
+ LastURL = 0x2,
+ LastURLSize = 0x3,
+ SharePostResult = 0x4,
+ PostServiceName = 0x5,
+ PostServiceNameSize = 0x6,
+ PostID = 0x7,
+ PostIDSize = 0x8,
+ MediaPlayerAutoClosedByCompletion = 0x9,
+};
+
+enum class DocumentKind : u32 {
+ OfflineHtmlPage = 1,
+ ApplicationLegalInformation = 2,
+ SystemDataPage = 3,
+};
+
+enum class ShareStartPage : u32 {
+ Default,
+ Settings,
+};
+
+enum class BootDisplayKind : u32 {
+ Default,
+ White,
+ Black,
+};
+
+enum class BackgroundKind : u32 {
+ Default,
+};
+
+enum class LeftStickMode : u32 {
+ Pointer,
+ Cursor,
+};
+
+enum class WebSessionBootMode : u32 {
+ AllForeground,
+ AllForegroundInitiallyHidden,
+};
+
+struct WebArgHeader {
+ u16 total_tlv_entries{};
+ INSERT_PADDING_BYTES(2);
+ ShimKind shim_kind{};
+};
+static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
+
+struct WebArgInputTLV {
+ WebArgInputTLVType input_tlv_type{};
+ u16 arg_data_size{};
+ INSERT_PADDING_WORDS(1);
+};
+static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size.");
+
+struct WebArgOutputTLV {
+ WebArgOutputTLVType output_tlv_type{};
+ u16 arg_data_size{};
+ INSERT_PADDING_WORDS(1);
+};
+static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size.");
+
+struct WebCommonReturnValue {
+ WebExitReason exit_reason{};
+ INSERT_PADDING_WORDS(1);
+ std::array<char, 0x1000> last_url{};
+ u64 last_url_size{};
+};
+static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
+
+using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
+
+} // namespace Service::AM::Applets