summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.travis/clang-format/script.sh2
-rw-r--r--src/common/web_result.h1
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/crypto/partition_data_manager.cpp4
-rw-r--r--src/core/file_sys/bis_factory.cpp12
-rw-r--r--src/core/file_sys/bis_factory.h8
-rw-r--r--src/core/file_sys/control_metadata.cpp13
-rw-r--r--src/core/file_sys/control_metadata.h1
-rw-r--r--src/core/file_sys/patch_manager.cpp2
-rw-r--r--src/core/file_sys/registered_cache.cpp14
-rw-r--r--src/core/file_sys/registered_cache.h12
-rw-r--r--src/core/file_sys/sdmc_factory.cpp8
-rw-r--r--src/core/file_sys/sdmc_factory.h4
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp18
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp13
-rw-r--r--src/core/hle/service/filesystem/filesystem.h8
-rw-r--r--src/core/hle/service/ns/pl_u.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp22
-rw-r--r--src/core/loader/loader.cpp3
-rw-r--r--src/core/loader/loader.h1
-rw-r--r--src/core/loader/nro.cpp10
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp23
-rw-r--r--src/core/loader/nso.h6
-rw-r--r--src/video_core/engines/shader_bytecode.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp8
-rw-r--r--src/web_service/telemetry_json.cpp90
-rw-r--r--src/web_service/telemetry_json.h24
-rw-r--r--src/web_service/verify_login.cpp1
-rw-r--r--src/web_service/web_backend.cpp235
-rw-r--r--src/web_service/web_backend.h58
-rw-r--r--src/yuzu/game_list_worker.cpp19
-rw-r--r--src/yuzu/game_list_worker.h2
-rw-r--r--src/yuzu/main.cpp10
35 files changed, 348 insertions, 297 deletions
diff --git a/.travis/clang-format/script.sh b/.travis/clang-format/script.sh
index 0f6e8e6e4..3eff6322f 100755
--- a/.travis/clang-format/script.sh
+++ b/.travis/clang-format/script.sh
@@ -1,6 +1,6 @@
#!/bin/bash -ex
-if grep -nr '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis* dist/*.desktop \
+if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis* dist/*.desktop \
dist/*.svg dist/*.xml; then
echo Trailing whitespace found, aborting
exit 1
diff --git a/src/common/web_result.h b/src/common/web_result.h
index 969926674..8bfa2141d 100644
--- a/src/common/web_result.h
+++ b/src/common/web_result.h
@@ -5,6 +5,7 @@
#pragma once
#include <string>
+#include "common/common_types.h"
namespace Common {
struct WebResult {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fddaafd1..78986deb5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -400,8 +400,8 @@ create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives)
if (ENABLE_WEB_SERVICE)
- add_definitions(-DENABLE_WEB_SERVICE)
- target_link_libraries(core PUBLIC json-headers web_service)
+ target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
+ target_link_libraries(core PRIVATE web_service)
endif()
if (ARCHITECTURE_x86_64)
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index ed5e2b145..25cee1f3a 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -303,8 +303,8 @@ FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir,
PartitionDataManager::PartitionDataManager(const FileSys::VirtualDir& sysdata_dir)
: boot0(FindFileInDirWithNames(sysdata_dir, "BOOT0")),
- fuses(FindFileInDirWithNames(sysdata_dir, "fuse")),
- kfuses(FindFileInDirWithNames(sysdata_dir, "kfuse")),
+ fuses(FindFileInDirWithNames(sysdata_dir, "fuses")),
+ kfuses(FindFileInDirWithNames(sysdata_dir, "kfuses")),
package2({
FindFileInDirWithNames(sysdata_dir, "BCPKG2-1-Normal-Main"),
FindFileInDirWithNames(sysdata_dir, "BCPKG2-2-Normal-Sub"),
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 6102ef476..76a2b7e86 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -10,19 +10,19 @@ namespace FileSys {
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_)
: nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
- sysnand_cache(std::make_shared<RegisteredCache>(
+ sysnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
- usrnand_cache(std::make_shared<RegisteredCache>(
+ usrnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {}
BISFactory::~BISFactory() = default;
-std::shared_ptr<RegisteredCache> BISFactory::GetSystemNANDContents() const {
- return sysnand_cache;
+RegisteredCache* BISFactory::GetSystemNANDContents() const {
+ return sysnand_cache.get();
}
-std::shared_ptr<RegisteredCache> BISFactory::GetUserNANDContents() const {
- return usrnand_cache;
+RegisteredCache* BISFactory::GetUserNANDContents() const {
+ return usrnand_cache.get();
}
VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index c352e0925..364d309bd 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -20,8 +20,8 @@ public:
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root);
~BISFactory();
- std::shared_ptr<RegisteredCache> GetSystemNANDContents() const;
- std::shared_ptr<RegisteredCache> GetUserNANDContents() const;
+ RegisteredCache* GetSystemNANDContents() const;
+ RegisteredCache* GetUserNANDContents() const;
VirtualDir GetModificationLoadRoot(u64 title_id) const;
@@ -29,8 +29,8 @@ private:
VirtualDir nand_root;
VirtualDir load_root;
- std::shared_ptr<RegisteredCache> sysnand_cache;
- std::shared_ptr<RegisteredCache> usrnand_cache;
+ std::unique_ptr<RegisteredCache> sysnand_cache;
+ std::unique_ptr<RegisteredCache> usrnand_cache;
};
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 5b1177a03..a012c2be9 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -17,11 +17,13 @@ const std::array<const char*, 15> LANGUAGE_NAMES = {
};
std::string LanguageEntry::GetApplicationName() const {
- return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200);
+ return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
+ application_name.size());
}
std::string LanguageEntry::GetDeveloperName() const {
- return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100);
+ return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(),
+ developer_name.size());
}
NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
@@ -56,7 +58,12 @@ u64 NACP::GetTitleId() const {
return raw->title_id;
}
+u64 NACP::GetDLCBaseTitleId() const {
+ return raw->dlc_base_title_id;
+}
+
std::string NACP::GetVersionString() const {
- return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 0x10);
+ return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
+ raw->version_string.size());
}
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 43d6f0719..141f7e056 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -79,6 +79,7 @@ public:
std::string GetApplicationName(Language language = Language::Default) const;
std::string GetDeveloperName(Language language = Language::Default) const;
u64 GetTitleId() const;
+ u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;
private:
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 019caebe9..c15ac8e19 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -346,7 +346,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
- const auto& installed{Service::FileSystem::GetUnionContents()};
+ const auto installed{Service::FileSystem::GetUnionContents()};
const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index e9b040689..1febb398e 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -308,14 +308,14 @@ VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
return GetEntryRaw(entry.title_id, entry.type);
}
-std::shared_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
+std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
return nullptr;
- return std::make_shared<NCA>(raw);
+ return std::make_unique<NCA>(raw);
}
-std::shared_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
+std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
return GetEntry(entry.title_id, entry.type);
}
@@ -516,7 +516,7 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
}) != yuzu_meta.end();
}
-RegisteredCacheUnion::RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches)
+RegisteredCacheUnion::RegisteredCacheUnion(std::vector<RegisteredCache*> caches)
: caches(std::move(caches)) {}
void RegisteredCacheUnion::Refresh() {
@@ -572,14 +572,14 @@ VirtualFile RegisteredCacheUnion::GetEntryRaw(RegisteredCacheEntry entry) const
return GetEntryRaw(entry.title_id, entry.type);
}
-std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const {
+std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const {
const auto raw = GetEntryRaw(title_id, type);
if (raw == nullptr)
return nullptr;
- return std::make_shared<NCA>(raw);
+ return std::make_unique<NCA>(raw);
}
-std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const {
+std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const {
return GetEntry(entry.title_id, entry.type);
}
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index c0cd59fc5..5ddacba47 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -88,8 +88,8 @@ public:
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
- std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
- std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
+ std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
+ std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::vector<RegisteredCacheEntry> ListEntries() const;
// If a parameter is not boost::none, it will be filtered for from all entries.
@@ -142,7 +142,7 @@ private:
// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface.
class RegisteredCacheUnion {
public:
- explicit RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches);
+ explicit RegisteredCacheUnion(std::vector<RegisteredCache*> caches);
void Refresh();
@@ -157,8 +157,8 @@ public:
VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
- std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
- std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
+ std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
+ std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
std::vector<RegisteredCacheEntry> ListEntries() const;
// If a parameter is not boost::none, it will be filtered for from all entries.
@@ -168,7 +168,7 @@ public:
boost::optional<u64> title_id = boost::none) const;
private:
- std::vector<std::shared_ptr<RegisteredCache>> caches;
+ std::vector<RegisteredCache*> caches;
};
} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index d66a9c9a4..bd3a57058 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -10,10 +10,10 @@
namespace FileSys {
SDMCFactory::SDMCFactory(VirtualDir dir_)
- : dir(std::move(dir_)), contents(std::make_shared<RegisteredCache>(
+ : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
[](const VirtualFile& file, const NcaID& id) {
- return std::make_shared<NAX>(file, id)->GetDecrypted();
+ return NAX{file, id}.GetDecrypted();
})) {}
SDMCFactory::~SDMCFactory() = default;
@@ -22,8 +22,8 @@ ResultVal<VirtualDir> SDMCFactory::Open() {
return MakeResult<VirtualDir>(dir);
}
-std::shared_ptr<RegisteredCache> SDMCFactory::GetSDMCContents() const {
- return contents;
+RegisteredCache* SDMCFactory::GetSDMCContents() const {
+ return contents.get();
}
} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index ea12149de..42794ba5b 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -19,12 +19,12 @@ public:
~SDMCFactory();
ResultVal<VirtualDir> Open();
- std::shared_ptr<RegisteredCache> GetSDMCContents() const;
+ RegisteredCache* GetSDMCContents() const;
private:
VirtualDir dir;
- std::shared_ptr<RegisteredCache> contents;
+ std::unique_ptr<RegisteredCache> contents;
};
} // namespace FileSys
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 0ecfb5af1..518161bf7 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -7,8 +7,10 @@
#include <vector>
#include "common/logging/log.h"
#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
+#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
@@ -19,7 +21,7 @@
namespace Service::AOC {
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
-constexpr u64 DLC_BASE_TO_AOC_ID_MASK = 0x1000;
+constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000;
static bool CheckAOCTitleIDMatchesBase(u64 base, u64 aoc) {
return (aoc & DLC_BASE_TITLE_ID_MASK) == base;
@@ -97,14 +99,24 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(out);
- IPC::ResponseBuilder rb{ctx, 2};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
+ rb.Push(count);
}
void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(Core::System::GetInstance().CurrentProcess()->GetTitleID() | DLC_BASE_TO_AOC_ID_MASK);
+ const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+ FileSys::PatchManager pm{title_id};
+
+ const auto res = pm.GetControlMetadata();
+ if (res.first == nullptr) {
+ rb.Push(title_id + DLC_BASE_TO_AOC_ID);
+ return;
+ }
+
+ rb.Push(res.first->GetDLCBaseTitleId());
}
void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e06712603..e32a7c48e 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -319,13 +319,12 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
-std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
- return std::make_shared<FileSys::RegisteredCacheUnion>(
- std::vector<std::shared_ptr<FileSys::RegisteredCache>>{
- GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
+std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
+ return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
+ GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
}
-std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() {
+FileSys::RegisteredCache* GetSystemNANDContents() {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
if (bis_factory == nullptr)
@@ -334,7 +333,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() {
return bis_factory->GetSystemNANDContents();
}
-std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() {
+FileSys::RegisteredCache* GetUserNANDContents() {
LOG_TRACE(Service_FS, "Opening User NAND Contents");
if (bis_factory == nullptr)
@@ -343,7 +342,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() {
return bis_factory->GetUserNANDContents();
}
-std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents() {
+FileSys::RegisteredCache* GetSDMCContents() {
LOG_TRACE(Service_FS, "Opening SDMC Contents");
if (sdmc_factory == nullptr)
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 2df1faeb0..6ca5c5636 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -47,11 +47,11 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
ResultVal<FileSys::VirtualDir> OpenSDMC();
-std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
+std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
-std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents();
-std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents();
-std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents();
+FileSys::RegisteredCache* GetSystemNANDContents();
+FileSys::RegisteredCache* GetUserNANDContents();
+FileSys::RegisteredCache* GetSDMCContents();
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 4b2f758a8..44accecb7 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -161,7 +161,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
};
RegisterHandlers(functions);
// Attempt to load shared font data from disk
- const auto nand = FileSystem::GetSystemNANDContents();
+ const auto* nand = FileSystem::GetSystemNANDContents();
std::size_t offset = 0;
// Rebuild shared fonts from data ncas
if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 951fd8257..8518dddcb 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -139,14 +139,22 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
const FileSys::VirtualFile module_file = dir->GetFile(module);
- if (module_file != nullptr) {
- const VAddr load_addr = next_load_addr;
- next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr,
- std::strcmp(module, "rtld") == 0, pm);
- LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
- // Register module with GDBStub
- GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
+ if (module_file == nullptr) {
+ continue;
}
+
+ const VAddr load_addr = next_load_addr;
+ const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
+ const auto tentative_next_load_addr =
+ AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm);
+ if (!tentative_next_load_addr) {
+ return ResultStatus::ErrorLoadingNSO;
+ }
+
+ next_load_addr = *tentative_next_load_addr;
+ LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
+ // Register module with GDBStub
+ GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
}
process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 91659ec17..9cd0b0ccd 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
-constexpr std::array<const char*, 59> RESULT_MESSAGES{
+constexpr std::array<const char*, 60> RESULT_MESSAGES{
"The operation completed successfully.",
"The loader requested to load is already loaded.",
"The operation is not implemented.",
@@ -128,6 +128,7 @@ constexpr std::array<const char*, 59> RESULT_MESSAGES{
"The RomFS could not be found.",
"The ELF file has incorrect size as determined by the header.",
"There was a general error loading the NRO into emulated memory.",
+ "There was a general error loading the NSO into emulated memory.",
"There is no icon available.",
"There is no control data available.",
"The NAX file has a bad header.",
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 0e0333db5..e562b3a04 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -90,6 +90,7 @@ enum class ResultStatus : u16 {
ErrorNoRomFS,
ErrorIncorrectELFFileSize,
ErrorLoadingNRO,
+ ErrorLoadingNSO,
ErrorNoIcon,
ErrorNoControl,
ErrorBadNAXHeader,
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 576fe692a..243b499f2 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -127,10 +127,10 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
}
-bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
+bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {
// Read NSO header
NroHeader nro_header{};
- if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
+ if (sizeof(NroHeader) != file.ReadObject(&nro_header)) {
return {};
}
if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) {
@@ -138,7 +138,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
}
// Build program image
- std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size));
+ std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size));
if (program_image.size() != PageAlignSize(nro_header.file_size)) {
return {};
}
@@ -182,7 +182,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
// Register module with GDBStub
- GDBStub::RegisterModule(file->GetName(), load_base, load_base);
+ GDBStub::RegisterModule(file.GetName(), load_base, load_base);
return true;
}
@@ -195,7 +195,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
// Load NRO
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- if (!LoadNro(file, base_address)) {
+ if (!LoadNro(*file, base_address)) {
return ResultStatus::ErrorLoadingNRO;
}
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 04b46119a..50ee5a78a 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -41,7 +41,7 @@ public:
bool IsRomFSUpdatable() const override;
private:
- bool LoadNro(FileSys::VirtualFile file, VAddr load_base);
+ bool LoadNro(const FileSys::VfsFile& file, VAddr load_base);
std::vector<u8> icon_data;
std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index ba57db9bf..68efca5c0 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -93,17 +93,14 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
}
-VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
- bool should_pass_arguments,
- boost::optional<FileSys::PatchManager> pm) {
- if (file == nullptr)
- return {};
-
- if (file->GetSize() < sizeof(NsoHeader))
+std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base,
+ bool should_pass_arguments,
+ std::optional<FileSys::PatchManager> pm) {
+ if (file.GetSize() < sizeof(NsoHeader))
return {};
NsoHeader nso_header{};
- if (sizeof(NsoHeader) != file->ReadObject(&nso_header))
+ if (sizeof(NsoHeader) != file.ReadObject(&nso_header))
return {};
if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
@@ -114,7 +111,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
std::vector<u8> program_image;
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
std::vector<u8> data =
- file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
+ file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
if (nso_header.IsSegmentCompressed(i)) {
data = DecompressSegment(data, nso_header.segments[i]);
}
@@ -157,7 +154,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
program_image.resize(image_size);
// Apply patches if necessary
- if (pm != boost::none && pm->HasNSOPatch(nso_header.build_id)) {
+ if (pm && pm->HasNSOPatch(nso_header.build_id)) {
std::vector<u8> pi_header(program_image.size() + 0x100);
std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader));
std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size());
@@ -172,7 +169,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
// Register module with GDBStub
- GDBStub::RegisterModule(file->GetName(), load_base, load_base);
+ GDBStub::RegisterModule(file.GetName(), load_base, load_base);
return load_base + image_size;
}
@@ -184,7 +181,9 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
// Load module
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- LoadModule(file, base_address, true);
+ if (!LoadModule(*file, base_address, true)) {
+ return ResultStatus::ErrorLoadingNSO;
+ }
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 70ab3b718..433306139 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -4,6 +4,7 @@
#pragma once
+#include <optional>
#include "common/common_types.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/linker.h"
@@ -36,8 +37,9 @@ public:
return IdentifyType(file);
}
- static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base, bool should_pass_arguments,
- boost::optional<FileSys::PatchManager> pm = boost::none);
+ static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base,
+ bool should_pass_arguments,
+ std::optional<FileSys::PatchManager> pm = {});
ResultStatus Load(Kernel::Process& process) override;
};
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 9a59b65b3..f356f9a03 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -267,7 +267,7 @@ enum class ControlCode : u64 {
GTU = 12,
NEU = 13,
GEU = 14,
- //
+ T = 15,
OFF = 16,
LO = 17,
SFF = 18,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 84582c777..8d5f277e2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -286,7 +286,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
&ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
// Bind the buffer
- glBindBufferRange(GL_UNIFORM_BUFFER, stage, buffer_cache.GetHandle(), offset, sizeof(ubo));
+ glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(stage), buffer_cache.GetHandle(),
+ offset, static_cast<GLsizeiptr>(sizeof(ubo)));
Shader shader{shader_cache.GetStageProgram(program)};
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8dfb49507..ca063d90d 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1436,7 +1436,6 @@ private:
break;
}
-
case OpCode::Type::Shift: {
std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true);
std::string op_b;
@@ -1478,7 +1477,6 @@ private:
}
break;
}
-
case OpCode::Type::ArithmeticIntegerImmediate: {
std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
std::string op_b = std::to_string(instr.alu.imm20_32.Value());
@@ -2626,14 +2624,14 @@ private:
const std::string pred =
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
- const std::string controlCode = regs.GetControlCode(instr.csetp.cc);
+ const std::string control_code = regs.GetControlCode(instr.csetp.cc);
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred3,
- '(' + controlCode + ") " + combiner + " (" + pred + ')');
+ '(' + control_code + ") " + combiner + " (" + pred + ')');
}
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred0,
- "!(" + controlCode + ") " + combiner + " (" + pred + ')');
+ "!(" + control_code + ") " + combiner + " (" + pred + ')');
}
break;
}
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index 033ea1ea4..0a8f2bd9e 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -2,96 +2,114 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <thread>
-#include "common/assert.h"
+#include <json.hpp>
#include "common/detached_tasks.h"
+#include "common/web_result.h"
#include "web_service/telemetry_json.h"
#include "web_service/web_backend.h"
namespace WebService {
-TelemetryJson::TelemetryJson(const std::string& host, const std::string& username,
- const std::string& token)
- : host(std::move(host)), username(std::move(username)), token(std::move(token)) {}
-TelemetryJson::~TelemetryJson() = default;
+struct TelemetryJson::Impl {
+ Impl(std::string host, std::string username, std::string token)
+ : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {}
-template <class T>
-void TelemetryJson::Serialize(Telemetry::FieldType type, const std::string& name, T value) {
- sections[static_cast<u8>(type)][name] = value;
-}
+ nlohmann::json& TopSection() {
+ return sections[static_cast<u8>(Telemetry::FieldType::None)];
+ }
-void TelemetryJson::SerializeSection(Telemetry::FieldType type, const std::string& name) {
- TopSection()[name] = sections[static_cast<unsigned>(type)];
-}
+ const nlohmann::json& TopSection() const {
+ return sections[static_cast<u8>(Telemetry::FieldType::None)];
+ }
+
+ template <class T>
+ void Serialize(Telemetry::FieldType type, const std::string& name, T value) {
+ sections[static_cast<u8>(type)][name] = value;
+ }
+
+ void SerializeSection(Telemetry::FieldType type, const std::string& name) {
+ TopSection()[name] = sections[static_cast<unsigned>(type)];
+ }
+
+ nlohmann::json output;
+ std::array<nlohmann::json, 7> sections;
+ std::string host;
+ std::string username;
+ std::string token;
+};
+
+TelemetryJson::TelemetryJson(std::string host, std::string username, std::string token)
+ : impl{std::make_unique<Impl>(std::move(host), std::move(username), std::move(token))} {}
+TelemetryJson::~TelemetryJson() = default;
void TelemetryJson::Visit(const Telemetry::Field<bool>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<double>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<float>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u8>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u16>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u32>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u64>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s8>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s16>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s32>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s64>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<std::string>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<const char*>& field) {
- Serialize(field.GetType(), field.GetName(), std::string(field.GetValue()));
+ impl->Serialize(field.GetType(), field.GetName(), std::string(field.GetValue()));
}
void TelemetryJson::Visit(const Telemetry::Field<std::chrono::microseconds>& field) {
- Serialize(field.GetType(), field.GetName(), field.GetValue().count());
+ impl->Serialize(field.GetType(), field.GetName(), field.GetValue().count());
}
void TelemetryJson::Complete() {
- SerializeSection(Telemetry::FieldType::App, "App");
- SerializeSection(Telemetry::FieldType::Session, "Session");
- SerializeSection(Telemetry::FieldType::Performance, "Performance");
- SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
- SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
- SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
-
- auto content = TopSection().dump();
+ impl->SerializeSection(Telemetry::FieldType::App, "App");
+ impl->SerializeSection(Telemetry::FieldType::Session, "Session");
+ impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
+ impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
+ impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
+ impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
+
+ auto content = impl->TopSection().dump();
// Send the telemetry async but don't handle the errors since they were written to the log
Common::DetachedTasks::AddTask(
- [host{this->host}, username{this->username}, token{this->token}, content]() {
+ [host{impl->host}, username{impl->username}, token{impl->token}, content]() {
Client{host, username, token}.PostJson("/telemetry", content, true);
});
}
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
index 0fe6f9a3e..93371414a 100644
--- a/src/web_service/telemetry_json.h
+++ b/src/web_service/telemetry_json.h
@@ -4,11 +4,9 @@
#pragma once
-#include <array>
+#include <chrono>
#include <string>
-#include <json.hpp>
#include "common/telemetry.h"
-#include "common/web_result.h"
namespace WebService {
@@ -18,8 +16,8 @@ namespace WebService {
*/
class TelemetryJson : public Telemetry::VisitorInterface {
public:
- TelemetryJson(const std::string& host, const std::string& username, const std::string& token);
- ~TelemetryJson();
+ TelemetryJson(std::string host, std::string username, std::string token);
+ ~TelemetryJson() override;
void Visit(const Telemetry::Field<bool>& field) override;
void Visit(const Telemetry::Field<double>& field) override;
@@ -39,20 +37,8 @@ public:
void Complete() override;
private:
- nlohmann::json& TopSection() {
- return sections[static_cast<u8>(Telemetry::FieldType::None)];
- }
-
- template <class T>
- void Serialize(Telemetry::FieldType type, const std::string& name, T value);
-
- void SerializeSection(Telemetry::FieldType type, const std::string& name);
-
- nlohmann::json output;
- std::array<nlohmann::json, 7> sections;
- std::string host;
- std::string username;
- std::string token;
+ struct Impl;
+ std::unique_ptr<Impl> impl;
};
} // namespace WebService
diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp
index 124aa3863..ca4b43b93 100644
--- a/src/web_service/verify_login.cpp
+++ b/src/web_service/verify_login.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <json.hpp>
+#include "common/web_result.h"
#include "web_service/verify_login.h"
#include "web_service/web_backend.h"
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index 787b0fbcb..b7737b615 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -3,9 +3,11 @@
// Refer to the license.txt file included.
#include <cstdlib>
+#include <mutex>
#include <string>
-#include <thread>
#include <LUrlParser.h>
+#include <httplib.h>
+#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/web_result.h"
#include "core/settings.h"
@@ -20,99 +22,132 @@ constexpr u32 HTTPS_PORT = 443;
constexpr u32 TIMEOUT_SECONDS = 30;
-Client::JWTCache Client::jwt_cache{};
+struct Client::Impl {
+ Impl(std::string host, std::string username, std::string token)
+ : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {
+ std::lock_guard<std::mutex> lock(jwt_cache.mutex);
+ if (this->username == jwt_cache.username && this->token == jwt_cache.token) {
+ jwt = jwt_cache.jwt;
+ }
+ }
+
+ /// A generic function handles POST, GET and DELETE request together
+ Common::WebResult GenericJson(const std::string& method, const std::string& path,
+ const std::string& data, bool allow_anonymous) {
+ if (jwt.empty()) {
+ UpdateJWT();
+ }
+
+ if (jwt.empty() && !allow_anonymous) {
+ LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
+ return Common::WebResult{Common::WebResult::Code::CredentialsMissing,
+ "Credentials needed"};
+ }
+
+ auto result = GenericJson(method, path, data, jwt);
+ if (result.result_string == "401") {
+ // Try again with new JWT
+ UpdateJWT();
+ result = GenericJson(method, path, data, jwt);
+ }
-Client::Client(const std::string& host, const std::string& username, const std::string& token)
- : host(host), username(username), token(token) {
- std::lock_guard<std::mutex> lock(jwt_cache.mutex);
- if (username == jwt_cache.username && token == jwt_cache.token) {
- jwt = jwt_cache.jwt;
+ return result;
}
-}
-Common::WebResult Client::GenericJson(const std::string& method, const std::string& path,
- const std::string& data, const std::string& jwt,
- const std::string& username, const std::string& token) {
- if (cli == nullptr) {
- auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
- int port;
- if (parsedUrl.m_Scheme == "http") {
- if (!parsedUrl.GetPort(&port)) {
- port = HTTP_PORT;
- }
- cli =
- std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port, TIMEOUT_SECONDS);
- } else if (parsedUrl.m_Scheme == "https") {
- if (!parsedUrl.GetPort(&port)) {
- port = HTTPS_PORT;
+ /**
+ * A generic function with explicit authentication method specified
+ * JWT is used if the jwt parameter is not empty
+ * username + token is used if jwt is empty but username and token are not empty
+ * anonymous if all of jwt, username and token are empty
+ */
+ Common::WebResult GenericJson(const std::string& method, const std::string& path,
+ const std::string& data, const std::string& jwt = "",
+ const std::string& username = "", const std::string& token = "") {
+ if (cli == nullptr) {
+ auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
+ int port;
+ if (parsedUrl.m_Scheme == "http") {
+ if (!parsedUrl.GetPort(&port)) {
+ port = HTTP_PORT;
+ }
+ cli = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port,
+ TIMEOUT_SECONDS);
+ } else if (parsedUrl.m_Scheme == "https") {
+ if (!parsedUrl.GetPort(&port)) {
+ port = HTTPS_PORT;
+ }
+ cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port,
+ TIMEOUT_SECONDS);
+ } else {
+ LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
+ return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme"};
}
- cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port,
- TIMEOUT_SECONDS);
- } else {
- LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
- return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme"};
}
- }
- if (cli == nullptr) {
- LOG_ERROR(WebService, "Invalid URL {}", host + path);
- return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL"};
- }
+ if (cli == nullptr) {
+ LOG_ERROR(WebService, "Invalid URL {}", host + path);
+ return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL"};
+ }
- httplib::Headers params;
- if (!jwt.empty()) {
- params = {
- {std::string("Authorization"), fmt::format("Bearer {}", jwt)},
- };
- } else if (!username.empty()) {
- params = {
- {std::string("x-username"), username},
- {std::string("x-token"), token},
+ httplib::Headers params;
+ if (!jwt.empty()) {
+ params = {
+ {std::string("Authorization"), fmt::format("Bearer {}", jwt)},
+ };
+ } else if (!username.empty()) {
+ params = {
+ {std::string("x-username"), username},
+ {std::string("x-token"), token},
+ };
+ }
+
+ params.emplace(std::string("api-version"),
+ std::string(API_VERSION.begin(), API_VERSION.end()));
+ if (method != "GET") {
+ params.emplace(std::string("Content-Type"), std::string("application/json"));
};
- }
- params.emplace(std::string("api-version"), std::string(API_VERSION.begin(), API_VERSION.end()));
- if (method != "GET") {
- params.emplace(std::string("Content-Type"), std::string("application/json"));
- };
+ httplib::Request request;
+ request.method = method;
+ request.path = path;
+ request.headers = params;
+ request.body = data;
- httplib::Request request;
- request.method = method;
- request.path = path;
- request.headers = params;
- request.body = data;
+ httplib::Response response;
- httplib::Response response;
+ if (!cli->send(request, response)) {
+ LOG_ERROR(WebService, "{} to {} returned null", method, host + path);
+ return Common::WebResult{Common::WebResult::Code::LibError, "Null response"};
+ }
- if (!cli->send(request, response)) {
- LOG_ERROR(WebService, "{} to {} returned null", method, host + path);
- return Common::WebResult{Common::WebResult::Code::LibError, "Null response"};
- }
+ if (response.status >= 400) {
+ LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path,
+ response.status);
+ return Common::WebResult{Common::WebResult::Code::HttpError,
+ std::to_string(response.status)};
+ }
- if (response.status >= 400) {
- LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path,
- response.status);
- return Common::WebResult{Common::WebResult::Code::HttpError,
- std::to_string(response.status)};
- }
+ auto content_type = response.headers.find("content-type");
- auto content_type = response.headers.find("content-type");
+ if (content_type == response.headers.end()) {
+ LOG_ERROR(WebService, "{} to {} returned no content", method, host + path);
+ return Common::WebResult{Common::WebResult::Code::WrongContent, ""};
+ }
- if (content_type == response.headers.end()) {
- LOG_ERROR(WebService, "{} to {} returned no content", method, host + path);
- return Common::WebResult{Common::WebResult::Code::WrongContent, ""};
+ if (content_type->second.find("application/json") == std::string::npos &&
+ content_type->second.find("text/html; charset=utf-8") == std::string::npos) {
+ LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
+ content_type->second);
+ return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"};
+ }
+ return Common::WebResult{Common::WebResult::Code::Success, "", response.body};
}
- if (content_type->second.find("application/json") == std::string::npos &&
- content_type->second.find("text/html; charset=utf-8") == std::string::npos) {
- LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
- content_type->second);
- return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"};
- }
- return Common::WebResult{Common::WebResult::Code::Success, "", response.body};
-}
+ // Retrieve a new JWT from given username and token
+ void UpdateJWT() {
+ if (username.empty() || token.empty()) {
+ return;
+ }
-void Client::UpdateJWT() {
- if (!username.empty() && !token.empty()) {
auto result = GenericJson("POST", "/jwt/internal", "", "", username, token);
if (result.result_code != Common::WebResult::Code::Success) {
LOG_ERROR(WebService, "UpdateJWT failed");
@@ -123,27 +158,39 @@ void Client::UpdateJWT() {
jwt_cache.jwt = jwt = result.returned_data;
}
}
-}
-Common::WebResult Client::GenericJson(const std::string& method, const std::string& path,
- const std::string& data, bool allow_anonymous) {
- if (jwt.empty()) {
- UpdateJWT();
- }
+ std::string host;
+ std::string username;
+ std::string token;
+ std::string jwt;
+ std::unique_ptr<httplib::Client> cli;
+
+ struct JWTCache {
+ std::mutex mutex;
+ std::string username;
+ std::string token;
+ std::string jwt;
+ };
+ static inline JWTCache jwt_cache;
+};
- if (jwt.empty() && !allow_anonymous) {
- LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
- return Common::WebResult{Common::WebResult::Code::CredentialsMissing, "Credentials needed"};
- }
+Client::Client(std::string host, std::string username, std::string token)
+ : impl{std::make_unique<Impl>(std::move(host), std::move(username), std::move(token))} {}
- auto result = GenericJson(method, path, data, jwt);
- if (result.result_string == "401") {
- // Try again with new JWT
- UpdateJWT();
- result = GenericJson(method, path, data, jwt);
- }
+Client::~Client() = default;
+
+Common::WebResult Client::PostJson(const std::string& path, const std::string& data,
+ bool allow_anonymous) {
+ return impl->GenericJson("POST", path, data, allow_anonymous);
+}
+
+Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
+ return impl->GenericJson("GET", path, "", allow_anonymous);
+}
- return result;
+Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data,
+ bool allow_anonymous) {
+ return impl->GenericJson("DELETE", path, data, allow_anonymous);
}
} // namespace WebService
diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h
index d75fbcc15..c637e09df 100644
--- a/src/web_service/web_backend.h
+++ b/src/web_service/web_backend.h
@@ -4,23 +4,19 @@
#pragma once
-#include <functional>
-#include <mutex>
+#include <memory>
#include <string>
-#include <tuple>
-#include <httplib.h>
-#include "common/common_types.h"
-#include "common/web_result.h"
-namespace httplib {
-class Client;
+namespace Common {
+struct WebResult;
}
namespace WebService {
class Client {
public:
- Client(const std::string& host, const std::string& username, const std::string& token);
+ Client(std::string host, std::string username, std::string token);
+ ~Client();
/**
* Posts JSON to the specified path.
@@ -30,9 +26,7 @@ public:
* @return the result of the request.
*/
Common::WebResult PostJson(const std::string& path, const std::string& data,
- bool allow_anonymous) {
- return GenericJson("POST", path, data, allow_anonymous);
- }
+ bool allow_anonymous);
/**
* Gets JSON from the specified path.
@@ -40,9 +34,7 @@ public:
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
* @return the result of the request.
*/
- Common::WebResult GetJson(const std::string& path, bool allow_anonymous) {
- return GenericJson("GET", path, "", allow_anonymous);
- }
+ Common::WebResult GetJson(const std::string& path, bool allow_anonymous);
/**
* Deletes JSON to the specified path.
@@ -52,41 +44,11 @@ public:
* @return the result of the request.
*/
Common::WebResult DeleteJson(const std::string& path, const std::string& data,
- bool allow_anonymous) {
- return GenericJson("DELETE", path, data, allow_anonymous);
- }
+ bool allow_anonymous);
private:
- /// A generic function handles POST, GET and DELETE request together
- Common::WebResult GenericJson(const std::string& method, const std::string& path,
- const std::string& data, bool allow_anonymous);
-
- /**
- * A generic function with explicit authentication method specified
- * JWT is used if the jwt parameter is not empty
- * username + token is used if jwt is empty but username and token are not empty
- * anonymous if all of jwt, username and token are empty
- */
- Common::WebResult GenericJson(const std::string& method, const std::string& path,
- const std::string& data, const std::string& jwt = "",
- const std::string& username = "", const std::string& token = "");
-
- // Retrieve a new JWT from given username and token
- void UpdateJWT();
-
- std::string host;
- std::string username;
- std::string token;
- std::string jwt;
- std::unique_ptr<httplib::Client> cli;
-
- struct JWTCache {
- std::mutex mutex;
- std::string username;
- std::string token;
- std::string jwt;
- };
- static JWTCache jwt_cache;
+ struct Impl;
+ std::unique_ptr<Impl> impl;
};
} // namespace WebService
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 8f99a1c78..3881aba5f 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -96,7 +96,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
FileSys::ContentRecordType::Program);
for (const auto& game : installed_games) {
- const auto& file = cache->GetEntryUnparsed(game);
+ const auto file = cache->GetEntryUnparsed(game);
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
if (!loader)
continue;
@@ -107,7 +107,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
loader->ReadProgramId(program_id);
const FileSys::PatchManager patch{program_id};
- const auto& control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
+ const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
if (control != nullptr)
GetMetadataFromControlNCA(patch, *control, icon, name);
@@ -135,9 +135,10 @@ void GameListWorker::AddInstalledTitlesToGameList() {
FileSys::ContentRecordType::Control);
for (const auto& entry : control_data) {
- const auto nca = cache->GetEntry(entry);
- if (nca != nullptr)
- nca_control_map.insert_or_assign(entry.title_id, nca);
+ auto nca = cache->GetEntry(entry);
+ if (nca != nullptr) {
+ nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
+ }
}
}
@@ -153,9 +154,11 @@ void GameListWorker::FillControlMap(const std::string& dir_path) {
QFileInfo file_info(physical_name.c_str());
if (!is_dir && file_info.suffix().toStdString() == "nca") {
auto nca =
- std::make_shared<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
- if (nca->GetType() == FileSys::NCAContentType::Control)
- nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
+ std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
+ if (nca->GetType() == FileSys::NCAContentType::Control) {
+ const u64 title_id = nca->GetTitleId();
+ nca_control_map.insert_or_assign(title_id, std::move(nca));
+ }
}
return true;
};
diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h
index 09d20c42f..0e42d0bde 100644
--- a/src/yuzu/game_list_worker.h
+++ b/src/yuzu/game_list_worker.h
@@ -63,7 +63,7 @@ private:
void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion = 0);
std::shared_ptr<FileSys::VfsFilesystem> vfs;
- std::map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map;
+ std::map<u64, std::unique_ptr<FileSys::NCA>> nca_control_map;
QStringList watch_list;
QString dir_path;
bool deep_scan;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cc92ea5b8..bef9df00d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1428,8 +1428,12 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
QMessageBox::warning(
this, tr("Warning Missing Derivation Components"),
tr("The following are missing from your configuration that may hinder key "
- "derivation. It will be attempted but may not complete.\n\n") +
- errors);
+ "derivation. It will be attempted but may not complete.<br><br>") +
+ errors +
+ tr("<br><br>You can get all of these and dump all of your games easily by "
+ "following <a href='https://yuzu-emu.org/help/quickstart/quickstart/'>the "
+ "quickstart guide</a>. Alternatively, you can use another method of dumping "
+ "to obtain all of your keys."));
}
QProgressDialog prog;
@@ -1563,7 +1567,7 @@ void GMainWindow::UpdateUITheme() {
emit UpdateThemedIcons();
}
-void GMainWindow::SetDiscordEnabled(bool state) {
+void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
#ifdef USE_DISCORD_PRESENCE
if (state) {
discord_rpc = std::make_unique<DiscordRPC::DiscordImpl>();