applets/web: Implement the offline browser applet backend

master
Morph 2020-11-12 12:23:46 +07:00
parent a5750f437d
commit 89df483567
2 changed files with 143 additions and 13 deletions

@ -2,16 +2,26 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <optional>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.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/web_browser.h" #include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/web_browser.h" #include "core/hle/service/am/applets/web_browser.h"
#include "core/hle/service/filesystem/filesystem.h"
namespace Service::AM::Applets { namespace Service::AM::Applets {
@ -36,6 +46,16 @@ std::string ParseStringValue(const std::vector<u8>& data) {
data.size()); data.size());
} }
std::string GetMainURL(const std::string& url) {
const auto index = url.find('?');
if (index == std::string::npos) {
return url;
}
return url.substr(0, index);
}
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) { WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
@ -72,15 +92,35 @@ WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_
return input_tlv_map; return input_tlv_map;
} }
std::optional<std::vector<u8>> GetInputTLVData(const WebArgInputTLVMap& input_tlv_map, FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
WebArgInputTLVType input_tlv_type) { FileSys::ContentRecordType nca_type) {
const auto map_it = input_tlv_map.find(input_tlv_type); if (nca_type == FileSys::ContentRecordType::Data) {
const auto nca =
system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type);
if (map_it == input_tlv_map.end()) { if (nca == nullptr) {
return std::nullopt; LOG_ERROR(Service_AM,
"NCA of type={} with title_id={:016X} is not found in the System NAND!",
nca_type, title_id);
return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
}
return nca->GetRomFS();
} else {
const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type);
if (nca == nullptr) {
LOG_ERROR(Service_AM,
"NCA of type={} with title_id={:016X} is not found in the ContentProvider!",
nca_type, title_id);
return nullptr;
}
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
return pm.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), nca_type);
} }
return map_it->second;
} }
} // namespace } // namespace
@ -209,11 +249,92 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
broker.SignalStateChanged(); broker.SignalStateChanged();
} }
bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const {
return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end();
}
std::optional<std::vector<u8>> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) {
const auto map_it = web_arg_input_tlv_map.find(input_tlv_type);
if (map_it == web_arg_input_tlv_map.end()) {
return std::nullopt;
}
return map_it->second;
}
void WebBrowser::InitializeShop() {} void WebBrowser::InitializeShop() {}
void WebBrowser::InitializeLogin() {} void WebBrowser::InitializeLogin() {}
void WebBrowser::InitializeOffline() {} void WebBrowser::InitializeOffline() {
const auto document_path =
ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value());
const auto document_kind =
ParseRawValue<DocumentKind>(GetInputTLVData(WebArgInputTLVType::DocumentKind).value());
u64 title_id{};
FileSys::ContentRecordType nca_type{FileSys::ContentRecordType::HtmlDocument};
std::string additional_paths;
switch (document_kind) {
case DocumentKind::OfflineHtmlPage:
title_id = system.CurrentProcess()->GetTitleID();
nca_type = FileSys::ContentRecordType::HtmlDocument;
additional_paths = "html-document";
break;
case DocumentKind::ApplicationLegalInformation:
title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::ApplicationID).value());
nca_type = FileSys::ContentRecordType::LegalInformation;
break;
case DocumentKind::SystemDataPage:
title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::SystemDataID).value());
nca_type = FileSys::ContentRecordType::Data;
break;
}
static constexpr std::array<const char*, 3> RESOURCE_TYPES{
"manual",
"legal_information",
"system_data",
};
offline_cache_dir = Common::FS::SanitizePath(
fmt::format("{}/offline_web_applet_{}/{:016X}",
Common::FS::GetUserPath(Common::FS::UserPath::CacheDir),
RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id),
Common::FS::DirectorySeparator::PlatformDefault);
offline_document = Common::FS::SanitizePath(
fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path),
Common::FS::DirectorySeparator::PlatformDefault);
const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document),
Common::FS::DirectorySeparator::PlatformDefault);
if (Common::FS::Exists(main_url)) {
return;
}
auto offline_romfs = GetOfflineRomFS(system, title_id, nca_type);
if (offline_romfs == nullptr) {
LOG_ERROR(Service_AM, "RomFS with title_id={:016X} and nca_type={} cannot be extracted!",
title_id, nca_type);
return;
}
LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir);
const auto extracted_romfs_dir =
FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
const auto temp_dir =
system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite);
FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir);
}
void WebBrowser::InitializeShare() {} void WebBrowser::InitializeShare() {}
@ -234,8 +355,8 @@ void WebBrowser::ExecuteLogin() {
} }
void WebBrowser::ExecuteOffline() { void WebBrowser::ExecuteOffline() {
LOG_WARNING(Service_AM, "(STUBBED) called, Offline Applet is not implemented"); LOG_INFO(Service_AM, "Opening offline document at {}", offline_document);
WebBrowserExit(WebExitReason::EndButtonPressed); WebBrowserExit(WebExitReason::WindowClosed);
} }
void WebBrowser::ExecuteShare() { void WebBrowser::ExecuteShare() {
@ -257,5 +378,4 @@ void WebBrowser::ExecuteLobby() {
LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed); WebBrowserExit(WebExitReason::EndButtonPressed);
} }
} // namespace Service::AM::Applets } // namespace Service::AM::Applets

@ -4,6 +4,8 @@
#pragma once #pragma once
#include <optional>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/result.h" #include "core/hle/result.h"
@ -32,6 +34,10 @@ public:
void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); void WebBrowserExit(WebExitReason exit_reason, std::string last_url = "");
private: private:
bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const;
std::optional<std::vector<u8>> GetInputTLVData(WebArgInputTLVType input_tlv_type);
// Initializers for the various types of browser applets // Initializers for the various types of browser applets
void InitializeShop(); void InitializeShop();
void InitializeLogin(); void InitializeLogin();
@ -56,9 +62,13 @@ private:
ResultCode status{RESULT_SUCCESS}; ResultCode status{RESULT_SUCCESS};
WebAppletVersion web_applet_version; WebAppletVersion web_applet_version;
WebExitReason web_exit_reason;
WebArgHeader web_arg_header; WebArgHeader web_arg_header;
WebArgInputTLVMap web_arg_input_tlv_map; WebArgInputTLVMap web_arg_input_tlv_map;
std::string offline_cache_dir;
std::string offline_document;
Core::System& system; Core::System& system;
}; };