From 675aa5f71929466d5aa214f00b76f436d53c2a0b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:16:02 -0400 Subject: [PATCH] web_browser: Correct structures and properly parse TLVs/ShimKind Much, much more HW-accurate and allows us to easily support all of the different web 'shim' types. --- .../hle/service/am/applets/web_browser.cpp | 220 +++++++++++++----- src/core/hle/service/am/applets/web_browser.h | 7 +- 2 files changed, 167 insertions(+), 60 deletions(-) diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7878f5136..6918bda02 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,186 @@ 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; - -struct WebBufferHeader { - u16 count; - INSERT_PADDING_BYTES(6); +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, }; -static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); -struct WebArgumentHeader { - u16 type; +enum class ShimKind : u32 { + Shop = 1, + Login = 2, + Offline = 3, + Share = 4, + Web = 5, + Wifi = 6, + Lobby = 7, +}; + +constexpr std::size_t SHIM_KIND_COUNT = 0x8; + +struct WebArgHeader { + u16 count; + INSERT_PADDING_BYTES(2); + ShimKind kind; +}; +static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); + +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 last_url; u64 last_url_size; }; -static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); +static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); -static std::vector GetArgumentDataForTagType(const std::vector& data, u16 type) { - WebBufferHeader header; - ASSERT(sizeof(WebBufferHeader) <= data.size()); - std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); +struct WebWifiPageArg { + INSERT_PADDING_BYTES(4); + std::array connection_test_url; + std::array initial_url; + std::array nifm_network_uuid; + u32 nifm_requirement; +}; +static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size."); - 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); +struct WebWifiReturnValue { + INSERT_PADDING_BYTES(4); + u32 result; +}; +static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size."); - if (arg.type == type) { - std::vector out(arg.size); - offset += arg.offset; - ASSERT(offset + arg.size <= data.size()); - std::memcpy(out.data(), data.data() + offset, out.size()); +enum class OfflineWebSource : u32 { + OfflineHtmlPage = 0x1, + ApplicationLegalInformation = 0x2, + SystemDataPage = 0x3, +}; + +enum class ShopWebTarget { + ApplicationInfo, + AddOnContentList, + SubscriptionList, + ConsumableItemList, + Home, + Settings, +}; + +namespace { + +std::map> GetWebArguments(const std::vector& arg) { + WebArgHeader header{}; + if (arg.size() < sizeof(WebArgHeader)) + return {}; + + std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); + + std::map> out; + u64 offset = sizeof(WebArgHeader); + for (std::size_t i = 0; i < header.count; ++i) { + WebArgTLV tlv{}; + if (arg.size() < (offset + sizeof(WebArgTLV))) return out; - } - offset += arg.offset + arg.size; + std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); + offset += sizeof(WebArgTLV); + + offset += tlv.offset; + if (arg.size() < (offset + tlv.size)) + return out; + + std::vector data(tlv.size); + std::memcpy(data.data(), arg.data() + offset, tlv.size); + offset += tlv.size; + + out.insert_or_assign(tlv.type, data); } - return {}; + return out; } -static FileSys::VirtualFile GetManualRomFS() { - auto& loader{Core::System::GetInstance().GetAppLoader()}; - - FileSys::VirtualFile out; - if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) - 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, + Core::Frontend::ECommerceApplet* frontend_e_commerce) + : frontend(frontend), frontend_e_commerce(frontend_e_commerce) {} WebBrowser::~WebBrowser() = default; @@ -111,24 +225,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(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 { diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 7e0f34c7d..2474675de 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -10,6 +10,9 @@ namespace Service::AM::Applets { +enum class ShimKind : u32; +enum class WebArgTLVType : u16; + class WebBrowser final : public Applet { public: WebBrowser(Core::Frontend::WebBrowserApplet& frontend); @@ -38,7 +41,9 @@ private: bool unpacked = false; ResultCode status = RESULT_SUCCESS; - FileSys::VirtualFile manual_romfs; + ShimKind kind; + std::map> args; + std::string temporary_dir; std::string filename; };