diff options
| author | 2019-06-05 12:16:02 -0400 | |
|---|---|---|
| committer | 2019-06-24 20:05:11 -0400 | |
| commit | 675aa5f71929466d5aa214f00b76f436d53c2a0b (patch) | |
| tree | 70553383a12f2d06d9c2c31fdd33584a28c647a8 | |
| parent | yuzu: Accept default applets for Parental Controls and ECommerce (diff) | |
| download | yuzu-675aa5f71929466d5aa214f00b76f436d53c2a0b.tar.gz yuzu-675aa5f71929466d5aa214f00b76f436d53c2a0b.tar.xz yuzu-675aa5f71929466d5aa214f00b76f436d53c2a0b.zip | |
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.
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.cpp | 222 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.h | 7 |
2 files changed, 168 insertions, 61 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 @@ | |||
| 19 | #include "core/file_sys/nca_metadata.h" | 19 | #include "core/file_sys/nca_metadata.h" |
| 20 | #include "core/file_sys/registered_cache.h" | 20 | #include "core/file_sys/registered_cache.h" |
| 21 | #include "core/file_sys/romfs.h" | 21 | #include "core/file_sys/romfs.h" |
| 22 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 22 | #include "core/file_sys/vfs_types.h" | 23 | #include "core/file_sys/vfs_types.h" |
| 24 | #include "core/frontend/applets/general_frontend.h" | ||
| 23 | #include "core/frontend/applets/web_browser.h" | 25 | #include "core/frontend/applets/web_browser.h" |
| 24 | #include "core/hle/kernel/process.h" | 26 | #include "core/hle/kernel/process.h" |
| 25 | #include "core/hle/service/am/applets/web_browser.h" | 27 | #include "core/hle/service/am/applets/web_browser.h" |
| @@ -28,74 +30,186 @@ | |||
| 28 | 30 | ||
| 29 | namespace Service::AM::Applets { | 31 | namespace Service::AM::Applets { |
| 30 | 32 | ||
| 31 | // TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not | 33 | enum class WebArgTLVType : u16 { |
| 32 | // parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, | 34 | InitialURL = 0x1, |
| 33 | // but some may be worth an implementation. | 35 | ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name. |
| 34 | constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; | 36 | CallbackURL = 0x3, |
| 37 | CallbackableURL = 0x4, | ||
| 38 | ApplicationID = 0x5, | ||
| 39 | DocumentPath = 0x6, | ||
| 40 | DocumentKind = 0x7, | ||
| 41 | SystemDataID = 0x8, | ||
| 42 | ShareStartPage = 0x9, | ||
| 43 | Whitelist = 0xA, | ||
| 44 | News = 0xB, | ||
| 45 | UserID = 0xE, | ||
| 46 | AlbumEntry0 = 0xF, | ||
| 47 | ScreenShotEnabled = 0x10, | ||
| 48 | EcClientCertEnabled = 0x11, | ||
| 49 | Unk12 = 0x12, | ||
| 50 | PlayReportEnabled = 0x13, | ||
| 51 | Unk14 = 0x14, | ||
| 52 | Unk15 = 0x15, | ||
| 53 | BootDisplayKind = 0x17, | ||
| 54 | BackgroundKind = 0x18, | ||
| 55 | FooterEnabled = 0x19, | ||
| 56 | PointerEnabled = 0x1A, | ||
| 57 | LeftStickMode = 0x1B, | ||
| 58 | KeyRepeatFrame1 = 0x1C, | ||
| 59 | KeyRepeatFrame2 = 0x1D, | ||
| 60 | BootAsMediaPlayerInv = 0x1E, | ||
| 61 | DisplayUrlKind = 0x1F, | ||
| 62 | BootAsMediaPlayer = 0x21, | ||
| 63 | ShopJumpEnabled = 0x22, | ||
| 64 | MediaAutoPlayEnabled = 0x23, | ||
| 65 | LobbyParameter = 0x24, | ||
| 66 | ApplicationAlbumEntry = 0x26, | ||
| 67 | JsExtensionEnabled = 0x27, | ||
| 68 | AdditionalCommentText = 0x28, | ||
| 69 | TouchEnabledOnContents = 0x29, | ||
| 70 | UserAgentAdditionalString = 0x2A, | ||
| 71 | AdditionalMediaData0 = 0x2B, | ||
| 72 | MediaPlayerAutoCloseEnabled = 0x2C, | ||
| 73 | PageCacheEnabled = 0x2D, | ||
| 74 | WebAudioEnabled = 0x2E, | ||
| 75 | Unk2F = 0x2F, | ||
| 76 | YouTubeVideoWhitelist = 0x31, | ||
| 77 | FooterFixedKind = 0x32, | ||
| 78 | PageFadeEnabled = 0x33, | ||
| 79 | MediaCreatorApplicationRatingAge = 0x34, | ||
| 80 | BootLoadingIconEnabled = 0x35, | ||
| 81 | PageScrollIndicationEnabled = 0x36, | ||
| 82 | MediaPlayerSpeedControlEnabled = 0x37, | ||
| 83 | AlbumEntry1 = 0x38, | ||
| 84 | AlbumEntry2 = 0x39, | ||
| 85 | AlbumEntry3 = 0x3A, | ||
| 86 | AdditionalMediaData1 = 0x3B, | ||
| 87 | AdditionalMediaData2 = 0x3C, | ||
| 88 | AdditionalMediaData3 = 0x3D, | ||
| 89 | BootFooterButton = 0x3E, | ||
| 90 | OverrideWebAudioVolume = 0x3F, | ||
| 91 | OverrideMediaAudioVolume = 0x40, | ||
| 92 | BootMode = 0x41, | ||
| 93 | WebSessionEnabled = 0x42, | ||
| 94 | }; | ||
| 95 | |||
| 96 | enum class ShimKind : u32 { | ||
| 97 | Shop = 1, | ||
| 98 | Login = 2, | ||
| 99 | Offline = 3, | ||
| 100 | Share = 4, | ||
| 101 | Web = 5, | ||
| 102 | Wifi = 6, | ||
| 103 | Lobby = 7, | ||
| 104 | }; | ||
| 105 | |||
| 106 | constexpr std::size_t SHIM_KIND_COUNT = 0x8; | ||
| 35 | 107 | ||
| 36 | struct WebBufferHeader { | 108 | struct WebArgHeader { |
| 37 | u16 count; | 109 | u16 count; |
| 38 | INSERT_PADDING_BYTES(6); | 110 | INSERT_PADDING_BYTES(2); |
| 111 | ShimKind kind; | ||
| 39 | }; | 112 | }; |
| 40 | static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); | 113 | static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); |
| 41 | 114 | ||
| 42 | struct WebArgumentHeader { | 115 | struct WebArgTLV { |
| 43 | u16 type; | 116 | WebArgTLVType type; |
| 44 | u16 size; | 117 | u16 size; |
| 45 | u32 offset; | 118 | u32 offset; |
| 46 | }; | 119 | }; |
| 47 | static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); | 120 | static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size."); |
| 48 | 121 | ||
| 49 | struct WebArgumentResult { | 122 | struct WebCommonReturnValue { |
| 50 | u32 result_code; | 123 | u32 result_code; |
| 124 | INSERT_PADDING_BYTES(0x4); | ||
| 51 | std::array<char, 0x1000> last_url; | 125 | std::array<char, 0x1000> last_url; |
| 52 | u64 last_url_size; | 126 | u64 last_url_size; |
| 53 | }; | 127 | }; |
| 54 | static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); | 128 | static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); |
| 55 | 129 | ||
| 56 | static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { | 130 | struct WebWifiPageArg { |
| 57 | WebBufferHeader header; | 131 | INSERT_PADDING_BYTES(4); |
| 58 | ASSERT(sizeof(WebBufferHeader) <= data.size()); | 132 | std::array<char, 0x100> connection_test_url; |
| 59 | std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); | 133 | std::array<char, 0x400> initial_url; |
| 60 | 134 | std::array<u8, 0x10> nifm_network_uuid; | |
| 61 | u64 offset = sizeof(WebBufferHeader); | 135 | u32 nifm_requirement; |
| 62 | for (u16 i = 0; i < header.count; ++i) { | 136 | }; |
| 63 | WebArgumentHeader arg; | 137 | static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size."); |
| 64 | ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); | 138 | |
| 65 | std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); | 139 | struct WebWifiReturnValue { |
| 66 | offset += sizeof(WebArgumentHeader); | 140 | INSERT_PADDING_BYTES(4); |
| 67 | 141 | u32 result; | |
| 68 | if (arg.type == type) { | 142 | }; |
| 69 | std::vector<u8> out(arg.size); | 143 | static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size."); |
| 70 | offset += arg.offset; | 144 | |
| 71 | ASSERT(offset + arg.size <= data.size()); | 145 | enum class OfflineWebSource : u32 { |
| 72 | std::memcpy(out.data(), data.data() + offset, out.size()); | 146 | OfflineHtmlPage = 0x1, |
| 147 | ApplicationLegalInformation = 0x2, | ||
| 148 | SystemDataPage = 0x3, | ||
| 149 | }; | ||
| 150 | |||
| 151 | enum class ShopWebTarget { | ||
| 152 | ApplicationInfo, | ||
| 153 | AddOnContentList, | ||
| 154 | SubscriptionList, | ||
| 155 | ConsumableItemList, | ||
| 156 | Home, | ||
| 157 | Settings, | ||
| 158 | }; | ||
| 159 | |||
| 160 | namespace { | ||
| 161 | |||
| 162 | std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) { | ||
| 163 | WebArgHeader header{}; | ||
| 164 | if (arg.size() < sizeof(WebArgHeader)) | ||
| 165 | return {}; | ||
| 166 | |||
| 167 | std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); | ||
| 168 | |||
| 169 | std::map<WebArgTLVType, std::vector<u8>> out; | ||
| 170 | u64 offset = sizeof(WebArgHeader); | ||
| 171 | for (std::size_t i = 0; i < header.count; ++i) { | ||
| 172 | WebArgTLV tlv{}; | ||
| 173 | if (arg.size() < (offset + sizeof(WebArgTLV))) | ||
| 73 | return out; | 174 | return out; |
| 74 | } | ||
| 75 | 175 | ||
| 76 | offset += arg.offset + arg.size; | 176 | std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); |
| 77 | } | 177 | offset += sizeof(WebArgTLV); |
| 78 | 178 | ||
| 79 | return {}; | 179 | offset += tlv.offset; |
| 80 | } | 180 | if (arg.size() < (offset + tlv.size)) |
| 181 | return out; | ||
| 81 | 182 | ||
| 82 | static FileSys::VirtualFile GetManualRomFS() { | 183 | std::vector<u8> data(tlv.size); |
| 83 | auto& loader{Core::System::GetInstance().GetAppLoader()}; | 184 | std::memcpy(data.data(), arg.data() + offset, tlv.size); |
| 185 | offset += tlv.size; | ||
| 84 | 186 | ||
| 85 | FileSys::VirtualFile out; | 187 | out.insert_or_assign(tlv.type, data); |
| 86 | if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) | 188 | } |
| 87 | return out; | ||
| 88 | 189 | ||
| 190 | return out; | ||
| 191 | } | ||
| 192 | |||
| 193 | FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) { | ||
| 89 | const auto& installed{Core::System::GetInstance().GetContentProvider()}; | 194 | const auto& installed{Core::System::GetInstance().GetContentProvider()}; |
| 90 | const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), | 195 | const auto res = installed.GetEntry(title_id, type); |
| 91 | FileSys::ContentRecordType::Manual); | ||
| 92 | 196 | ||
| 93 | if (res != nullptr) | 197 | if (res != nullptr) { |
| 94 | return res->GetRomFS(); | 198 | return res->GetRomFS(); |
| 199 | } | ||
| 200 | |||
| 201 | if (type == FileSys::ContentRecordType::Data) { | ||
| 202 | return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | ||
| 203 | } | ||
| 204 | |||
| 95 | return nullptr; | 205 | return nullptr; |
| 96 | } | 206 | } |
| 97 | 207 | ||
| 98 | WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} | 208 | } // Anonymous namespace |
| 209 | |||
| 210 | WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, | ||
| 211 | Core::Frontend::ECommerceApplet* frontend_e_commerce) | ||
| 212 | : frontend(frontend), frontend_e_commerce(frontend_e_commerce) {} | ||
| 99 | 213 | ||
| 100 | WebBrowser::~WebBrowser() = default; | 214 | WebBrowser::~WebBrowser() = default; |
| 101 | 215 | ||
| @@ -111,24 +225,12 @@ void WebBrowser::Initialize() { | |||
| 111 | ASSERT(web_arg_storage != nullptr); | 225 | ASSERT(web_arg_storage != nullptr); |
| 112 | const auto& web_arg = web_arg_storage->GetData(); | 226 | const auto& web_arg = web_arg_storage->GetData(); |
| 113 | 227 | ||
| 114 | const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); | 228 | ASSERT(web_arg.size() >= 0x8); |
| 115 | filename = Common::StringFromFixedZeroTerminatedBuffer( | 229 | std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind)); |
| 116 | reinterpret_cast<const char*>(url_data.data()), url_data.size()); | ||
| 117 | 230 | ||
| 118 | temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + | 231 | args = GetWebArguments(web_arg); |
| 119 | "web_applet_manual", | ||
| 120 | FileUtil::DirectorySeparator::PlatformDefault); | ||
| 121 | FileUtil::DeleteDirRecursively(temporary_dir); | ||
| 122 | |||
| 123 | manual_romfs = GetManualRomFS(); | ||
| 124 | if (manual_romfs == nullptr) { | ||
| 125 | status = ResultCode(-1); | ||
| 126 | LOG_ERROR(Service_AM, "Failed to find manual for current process!"); | ||
| 127 | } | ||
| 128 | 232 | ||
| 129 | filename = | 233 | InitializeInternal(); |
| 130 | FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, | ||
| 131 | FileUtil::DirectorySeparator::PlatformDefault); | ||
| 132 | } | 234 | } |
| 133 | 235 | ||
| 134 | bool WebBrowser::TransactionComplete() const { | 236 | 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 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::AM::Applets { | 11 | namespace Service::AM::Applets { |
| 12 | 12 | ||
| 13 | enum class ShimKind : u32; | ||
| 14 | enum class WebArgTLVType : u16; | ||
| 15 | |||
| 13 | class WebBrowser final : public Applet { | 16 | class WebBrowser final : public Applet { |
| 14 | public: | 17 | public: |
| 15 | WebBrowser(Core::Frontend::WebBrowserApplet& frontend); | 18 | WebBrowser(Core::Frontend::WebBrowserApplet& frontend); |
| @@ -38,7 +41,9 @@ private: | |||
| 38 | bool unpacked = false; | 41 | bool unpacked = false; |
| 39 | ResultCode status = RESULT_SUCCESS; | 42 | ResultCode status = RESULT_SUCCESS; |
| 40 | 43 | ||
| 41 | FileSys::VirtualFile manual_romfs; | 44 | ShimKind kind; |
| 45 | std::map<WebArgTLVType, std::vector<u8>> args; | ||
| 46 | |||
| 42 | std::string temporary_dir; | 47 | std::string temporary_dir; |
| 43 | std::string filename; | 48 | std::string filename; |
| 44 | }; | 49 | }; |