diff options
| author | 2020-11-12 12:23:46 -0500 | |
|---|---|---|
| committer | 2020-12-18 10:33:27 -0500 | |
| commit | 89df4835673a2c6b1905459b2aff866a6caeec4a (patch) | |
| tree | e8f904ccdec94005cad6641771f79c788a55b35b /src | |
| parent | applets/web: Initial implementation of the web browser applet (diff) | |
| download | yuzu-89df4835673a2c6b1905459b2aff866a6caeec4a.tar.gz yuzu-89df4835673a2c6b1905459b2aff866a6caeec4a.tar.xz yuzu-89df4835673a2c6b1905459b2aff866a6caeec4a.zip | |
applets/web: Implement the offline browser applet backend
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.cpp | 146 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.h | 10 |
2 files changed, 143 insertions, 13 deletions
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7f398254e..06fcf3e3f 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -2,16 +2,26 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <optional> | ||
| 6 | |||
| 7 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/common_paths.h" | ||
| 7 | #include "common/file_util.h" | ||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/string_util.h" | 9 | #include "common/string_util.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/file_sys/content_archive.h" | ||
| 12 | #include "core/file_sys/mode.h" | ||
| 13 | #include "core/file_sys/nca_metadata.h" | ||
| 14 | #include "core/file_sys/patch_manager.h" | ||
| 15 | #include "core/file_sys/registered_cache.h" | ||
| 16 | #include "core/file_sys/romfs.h" | ||
| 17 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 18 | #include "core/file_sys/vfs_types.h" | ||
| 11 | #include "core/frontend/applets/web_browser.h" | 19 | #include "core/frontend/applets/web_browser.h" |
| 20 | #include "core/hle/kernel/process.h" | ||
| 12 | #include "core/hle/result.h" | 21 | #include "core/hle/result.h" |
| 13 | #include "core/hle/service/am/am.h" | 22 | #include "core/hle/service/am/am.h" |
| 14 | #include "core/hle/service/am/applets/web_browser.h" | 23 | #include "core/hle/service/am/applets/web_browser.h" |
| 24 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 15 | 25 | ||
| 16 | namespace Service::AM::Applets { | 26 | namespace Service::AM::Applets { |
| 17 | 27 | ||
| @@ -36,6 +46,16 @@ std::string ParseStringValue(const std::vector<u8>& data) { | |||
| 36 | data.size()); | 46 | data.size()); |
| 37 | } | 47 | } |
| 38 | 48 | ||
| 49 | std::string GetMainURL(const std::string& url) { | ||
| 50 | const auto index = url.find('?'); | ||
| 51 | |||
| 52 | if (index == std::string::npos) { | ||
| 53 | return url; | ||
| 54 | } | ||
| 55 | |||
| 56 | return url.substr(0, index); | ||
| 57 | } | ||
| 58 | |||
| 39 | WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) { | 59 | WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) { |
| 40 | std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); | 60 | std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); |
| 41 | 61 | ||
| @@ -72,15 +92,35 @@ WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_ | |||
| 72 | return input_tlv_map; | 92 | return input_tlv_map; |
| 73 | } | 93 | } |
| 74 | 94 | ||
| 75 | std::optional<std::vector<u8>> GetInputTLVData(const WebArgInputTLVMap& input_tlv_map, | 95 | FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, |
| 76 | WebArgInputTLVType input_tlv_type) { | 96 | FileSys::ContentRecordType nca_type) { |
| 77 | const auto map_it = input_tlv_map.find(input_tlv_type); | 97 | if (nca_type == FileSys::ContentRecordType::Data) { |
| 98 | const auto nca = | ||
| 99 | system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type); | ||
| 100 | |||
| 101 | if (nca == nullptr) { | ||
| 102 | LOG_ERROR(Service_AM, | ||
| 103 | "NCA of type={} with title_id={:016X} is not found in the System NAND!", | ||
| 104 | nca_type, title_id); | ||
| 105 | return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | ||
| 106 | } | ||
| 78 | 107 | ||
| 79 | if (map_it == input_tlv_map.end()) { | 108 | return nca->GetRomFS(); |
| 80 | return std::nullopt; | 109 | } else { |
| 81 | } | 110 | const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type); |
| 82 | 111 | ||
| 83 | return map_it->second; | 112 | if (nca == nullptr) { |
| 113 | LOG_ERROR(Service_AM, | ||
| 114 | "NCA of type={} with title_id={:016X} is not found in the ContentProvider!", | ||
| 115 | nca_type, title_id); | ||
| 116 | return nullptr; | ||
| 117 | } | ||
| 118 | |||
| 119 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), | ||
| 120 | system.GetContentProvider()}; | ||
| 121 | |||
| 122 | return pm.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), nca_type); | ||
| 123 | } | ||
| 84 | } | 124 | } |
| 85 | 125 | ||
| 86 | } // namespace | 126 | } // namespace |
| @@ -209,11 +249,92 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) | |||
| 209 | broker.SignalStateChanged(); | 249 | broker.SignalStateChanged(); |
| 210 | } | 250 | } |
| 211 | 251 | ||
| 252 | bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const { | ||
| 253 | return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end(); | ||
| 254 | } | ||
| 255 | |||
| 256 | std::optional<std::vector<u8>> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) { | ||
| 257 | const auto map_it = web_arg_input_tlv_map.find(input_tlv_type); | ||
| 258 | |||
| 259 | if (map_it == web_arg_input_tlv_map.end()) { | ||
| 260 | return std::nullopt; | ||
| 261 | } | ||
| 262 | |||
| 263 | return map_it->second; | ||
| 264 | } | ||
| 265 | |||
| 212 | void WebBrowser::InitializeShop() {} | 266 | void WebBrowser::InitializeShop() {} |
| 213 | 267 | ||
| 214 | void WebBrowser::InitializeLogin() {} | 268 | void WebBrowser::InitializeLogin() {} |
| 215 | 269 | ||
| 216 | void WebBrowser::InitializeOffline() {} | 270 | void WebBrowser::InitializeOffline() { |
| 271 | const auto document_path = | ||
| 272 | ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value()); | ||
| 273 | |||
| 274 | const auto document_kind = | ||
| 275 | ParseRawValue<DocumentKind>(GetInputTLVData(WebArgInputTLVType::DocumentKind).value()); | ||
| 276 | |||
| 277 | u64 title_id{}; | ||
| 278 | FileSys::ContentRecordType nca_type{FileSys::ContentRecordType::HtmlDocument}; | ||
| 279 | std::string additional_paths; | ||
| 280 | |||
| 281 | switch (document_kind) { | ||
| 282 | case DocumentKind::OfflineHtmlPage: | ||
| 283 | title_id = system.CurrentProcess()->GetTitleID(); | ||
| 284 | nca_type = FileSys::ContentRecordType::HtmlDocument; | ||
| 285 | additional_paths = "html-document"; | ||
| 286 | break; | ||
| 287 | case DocumentKind::ApplicationLegalInformation: | ||
| 288 | title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::ApplicationID).value()); | ||
| 289 | nca_type = FileSys::ContentRecordType::LegalInformation; | ||
| 290 | break; | ||
| 291 | case DocumentKind::SystemDataPage: | ||
| 292 | title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::SystemDataID).value()); | ||
| 293 | nca_type = FileSys::ContentRecordType::Data; | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | |||
| 297 | static constexpr std::array<const char*, 3> RESOURCE_TYPES{ | ||
| 298 | "manual", | ||
| 299 | "legal_information", | ||
| 300 | "system_data", | ||
| 301 | }; | ||
| 302 | |||
| 303 | offline_cache_dir = Common::FS::SanitizePath( | ||
| 304 | fmt::format("{}/offline_web_applet_{}/{:016X}", | ||
| 305 | Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), | ||
| 306 | RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id), | ||
| 307 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 308 | |||
| 309 | offline_document = Common::FS::SanitizePath( | ||
| 310 | fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path), | ||
| 311 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 312 | |||
| 313 | const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document), | ||
| 314 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 315 | |||
| 316 | if (Common::FS::Exists(main_url)) { | ||
| 317 | return; | ||
| 318 | } | ||
| 319 | |||
| 320 | auto offline_romfs = GetOfflineRomFS(system, title_id, nca_type); | ||
| 321 | |||
| 322 | if (offline_romfs == nullptr) { | ||
| 323 | LOG_ERROR(Service_AM, "RomFS with title_id={:016X} and nca_type={} cannot be extracted!", | ||
| 324 | title_id, nca_type); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir); | ||
| 329 | |||
| 330 | const auto extracted_romfs_dir = | ||
| 331 | FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); | ||
| 332 | |||
| 333 | const auto temp_dir = | ||
| 334 | system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite); | ||
| 335 | |||
| 336 | FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); | ||
| 337 | } | ||
| 217 | 338 | ||
| 218 | void WebBrowser::InitializeShare() {} | 339 | void WebBrowser::InitializeShare() {} |
| 219 | 340 | ||
| @@ -234,8 +355,8 @@ void WebBrowser::ExecuteLogin() { | |||
| 234 | } | 355 | } |
| 235 | 356 | ||
| 236 | void WebBrowser::ExecuteOffline() { | 357 | void WebBrowser::ExecuteOffline() { |
| 237 | LOG_WARNING(Service_AM, "(STUBBED) called, Offline Applet is not implemented"); | 358 | LOG_INFO(Service_AM, "Opening offline document at {}", offline_document); |
| 238 | WebBrowserExit(WebExitReason::EndButtonPressed); | 359 | WebBrowserExit(WebExitReason::WindowClosed); |
| 239 | } | 360 | } |
| 240 | 361 | ||
| 241 | void WebBrowser::ExecuteShare() { | 362 | void WebBrowser::ExecuteShare() { |
| @@ -257,5 +378,4 @@ void WebBrowser::ExecuteLobby() { | |||
| 257 | LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); | 378 | LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); |
| 258 | WebBrowserExit(WebExitReason::EndButtonPressed); | 379 | WebBrowserExit(WebExitReason::EndButtonPressed); |
| 259 | } | 380 | } |
| 260 | |||
| 261 | } // namespace Service::AM::Applets | 381 | } // 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 a1ed5fd1d..c36c717f1 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <optional> | ||
| 8 | |||
| 7 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 9 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| @@ -32,6 +34,10 @@ public: | |||
| 32 | void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); | 34 | void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); |
| 33 | 35 | ||
| 34 | private: | 36 | private: |
| 37 | bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const; | ||
| 38 | |||
| 39 | std::optional<std::vector<u8>> GetInputTLVData(WebArgInputTLVType input_tlv_type); | ||
| 40 | |||
| 35 | // Initializers for the various types of browser applets | 41 | // Initializers for the various types of browser applets |
| 36 | void InitializeShop(); | 42 | void InitializeShop(); |
| 37 | void InitializeLogin(); | 43 | void InitializeLogin(); |
| @@ -56,9 +62,13 @@ private: | |||
| 56 | ResultCode status{RESULT_SUCCESS}; | 62 | ResultCode status{RESULT_SUCCESS}; |
| 57 | 63 | ||
| 58 | WebAppletVersion web_applet_version; | 64 | WebAppletVersion web_applet_version; |
| 65 | WebExitReason web_exit_reason; | ||
| 59 | WebArgHeader web_arg_header; | 66 | WebArgHeader web_arg_header; |
| 60 | WebArgInputTLVMap web_arg_input_tlv_map; | 67 | WebArgInputTLVMap web_arg_input_tlv_map; |
| 61 | 68 | ||
| 69 | std::string offline_cache_dir; | ||
| 70 | std::string offline_document; | ||
| 71 | |||
| 62 | Core::System& system; | 72 | Core::System& system; |
| 63 | }; | 73 | }; |
| 64 | 74 | ||