Compare commits
10 Commits
main
..
d410c4355d
| Author | SHA1 | Date | |
|---|---|---|---|
| d410c4355d | |||
| 6f8ede035f | |||
| 836956394a | |||
| 9b18a32b0c | |||
| 82df796a4a | |||
| 33a1ce73af | |||
| 9339e7dbfe | |||
| dc65a4c8a9 | |||
| 895fee6235 | |||
| b5c506cf03 |
@@ -27,10 +27,10 @@ struct User {
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace account {
|
namespace Account {
|
||||||
Result init();
|
Result init();
|
||||||
void exit();
|
void exit();
|
||||||
std::vector<AccountUid> ids();
|
std::vector<AccountUid> ids();
|
||||||
std::string username(AccountUid id);
|
std::string username(AccountUid id);
|
||||||
std::string iconPath(AccountUid id);
|
std::string iconPath(AccountUid id);
|
||||||
} // namespace account
|
} // namespace Account
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ void servicesExit();
|
|||||||
Result servicesInit();
|
Result servicesInit();
|
||||||
void blinkLed(u8 times);
|
void blinkLed(u8 times);
|
||||||
|
|
||||||
namespace string_utils {
|
namespace StringUtils {
|
||||||
bool containsInvalidChar(const std::string& str);
|
bool containsInvalidChar(const std::string& str);
|
||||||
std::string format(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
|
std::string format(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||||
std::string removeForbiddenCharacters(std::string src);
|
std::string removeForbiddenCharacters(std::string src);
|
||||||
@@ -19,4 +19,4 @@ namespace string_utils {
|
|||||||
std::string removeNotAscii(std::string str);
|
std::string removeNotAscii(std::string str);
|
||||||
std::u16string UTF8toUTF16(const char* src);
|
std::u16string UTF8toUTF16(const char* src);
|
||||||
std::string elide(const std::string& s, size_t max_chars);
|
std::string elide(const std::string& s, size_t max_chars);
|
||||||
} // namespace string_utils
|
} // namespace StringUtils
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
||||||
namespace file_system {
|
namespace FileSystem {
|
||||||
Result mount(FsFileSystem* fs, u64 title_id, AccountUid uid);
|
Result mount(FsFileSystem* fs, u64 title_id, AccountUid uid);
|
||||||
int mount(FsFileSystem fs);
|
int mount(FsFileSystem fs);
|
||||||
void unmount();
|
void unmount();
|
||||||
} // namespace file_system
|
} // namespace FileSystem
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
// New API — use these going forward.
|
// New API — use these going forward.
|
||||||
namespace nxst::log {
|
namespace nxst::log {
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ namespace ui {
|
|||||||
userName->SetVisible(show);
|
userName->SetVisible(show);
|
||||||
if (show) {
|
if (show) {
|
||||||
userName->SetText(name);
|
userName->SetText(name);
|
||||||
std::string path = account::iconPath(*uid);
|
std::string path = Account::iconPath(*uid);
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
avatar->SetImage(path);
|
avatar->SetImage(path);
|
||||||
avatar->SetWidth(32);
|
avatar->SetWidth(32);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace ui {
|
|||||||
PU_SMART_CTOR(TransferOverlay)
|
PU_SMART_CTOR(TransferOverlay)
|
||||||
|
|
||||||
void SetStatus(const std::string& status) {
|
void SetStatus(const std::string& status) {
|
||||||
statusText->SetText(string_utils::elide(status, 56));
|
statusText->SetText(StringUtils::elide(status, 56));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetProgress(double val) {
|
void SetProgress(double val) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
static std::map<AccountUid, User> s_users;
|
static std::map<AccountUid, User> s_users;
|
||||||
|
|
||||||
Result account::init() {
|
Result Account::init() {
|
||||||
Result res = accountInitialize(AccountServiceType_Application);
|
Result res = accountInitialize(AccountServiceType_Application);
|
||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
return res;
|
return res;
|
||||||
@@ -24,11 +24,11 @@ Result account::init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void account::exit() {
|
void Account::exit() {
|
||||||
accountExit();
|
accountExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AccountUid> account::ids() {
|
std::vector<AccountUid> Account::ids() {
|
||||||
std::vector<AccountUid> result;
|
std::vector<AccountUid> result;
|
||||||
result.reserve(s_users.size());
|
result.reserve(s_users.size());
|
||||||
for (const auto& pair : s_users) {
|
for (const auto& pair : s_users) {
|
||||||
@@ -51,7 +51,7 @@ static User fetchUser(AccountUid id) {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string account::username(AccountUid id) {
|
std::string Account::username(AccountUid id) {
|
||||||
auto it = s_users.find(id);
|
auto it = s_users.find(id);
|
||||||
if (it == s_users.end()) {
|
if (it == s_users.end()) {
|
||||||
User user = fetchUser(id);
|
User user = fetchUser(id);
|
||||||
@@ -61,7 +61,7 @@ std::string account::username(AccountUid id) {
|
|||||||
return it->second.name;
|
return it->second.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string account::iconPath(AccountUid id) {
|
std::string Account::iconPath(AccountUid id) {
|
||||||
char path[128];
|
char path[128];
|
||||||
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg", id.uid[0], id.uid[1]);
|
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg", id.uid[0], id.uid[1]);
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "nxst/domain/account.hpp"
|
#include "nxst/domain/account.hpp"
|
||||||
|
#include <nxst/domain/util.hpp>
|
||||||
#include <nxst/domain/title.hpp>
|
#include <nxst/domain/title.hpp>
|
||||||
#include <nxst/domain/util.hpp>
|
#include <nxst/domain/util.hpp>
|
||||||
#include <nxst/infra/fs/directory.hpp>
|
#include <nxst/infra/fs/directory.hpp>
|
||||||
@@ -21,22 +22,22 @@ void Title::init(u8 save_data_type, u64 title_id, AccountUid uid, const std::str
|
|||||||
m_id = title_id;
|
m_id = title_id;
|
||||||
m_uid = uid;
|
m_uid = uid;
|
||||||
m_save_data_type = save_data_type;
|
m_save_data_type = save_data_type;
|
||||||
m_user_name = account::username(uid);
|
m_user_name = Account::username(uid);
|
||||||
m_author = author;
|
m_author = author;
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_safe_name = string_utils::containsInvalidChar(name) ? string_utils::format("0x%016llX", m_id)
|
m_safe_name = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", m_id)
|
||||||
: string_utils::removeForbiddenCharacters(name);
|
: StringUtils::removeForbiddenCharacters(name);
|
||||||
m_path = "sdmc:/switch/NXST/saves/" + string_utils::format("0x%016llX", m_id) + " " + m_safe_name;
|
m_path = "sdmc:/switch/NXST/saves/" + StringUtils::format("0x%016llX", m_id) + " " + m_safe_name;
|
||||||
|
|
||||||
std::string aname = string_utils::removeAccents(m_name);
|
std::string aname = StringUtils::removeAccents(m_name);
|
||||||
m_display_name = {aname, ""};
|
m_display_name = {aname, ""};
|
||||||
|
|
||||||
size_t colon = aname.rfind(':');
|
size_t colon = aname.rfind(':');
|
||||||
if (colon != std::string::npos) {
|
if (colon != std::string::npos) {
|
||||||
std::string head = aname.substr(0, colon);
|
std::string head = aname.substr(0, colon);
|
||||||
std::string tail = aname.substr(colon + 1);
|
std::string tail = aname.substr(colon + 1);
|
||||||
string_utils::trim(head);
|
StringUtils::trim(head);
|
||||||
string_utils::trim(tail);
|
StringUtils::trim(tail);
|
||||||
m_display_name = {head, tail};
|
m_display_name = {head, tail};
|
||||||
} else {
|
} else {
|
||||||
size_t open = aname.rfind('(');
|
size_t open = aname.rfind('(');
|
||||||
@@ -44,8 +45,8 @@ void Title::init(u8 save_data_type, u64 title_id, AccountUid uid, const std::str
|
|||||||
if (open != std::string::npos && close != std::string::npos && close > open) {
|
if (open != std::string::npos && close != std::string::npos && close > open) {
|
||||||
std::string head = aname.substr(0, open);
|
std::string head = aname.substr(0, open);
|
||||||
std::string paren = aname.substr(open + 1, close - open - 1);
|
std::string paren = aname.substr(open + 1, close - open - 1);
|
||||||
string_utils::trim(head);
|
StringUtils::trim(head);
|
||||||
string_utils::trim(paren);
|
StringUtils::trim(paren);
|
||||||
m_display_name = {head, paren};
|
m_display_name = {head, paren};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +105,7 @@ void Title::lastPlayedTimestamp(u32 ts) {
|
|||||||
|
|
||||||
std::string Title::playTime() const {
|
std::string Title::playTime() const {
|
||||||
const u64 minutes = m_play_time_ns / 60000000000ULL;
|
const u64 minutes = m_play_time_ns / 60000000000ULL;
|
||||||
return string_utils::format("%d", minutes / 60) + ":" + string_utils::format("%02d", minutes % 60) +
|
return StringUtils::format("%d", minutes / 60) + ":" + StringUtils::format("%02d", minutes % 60) +
|
||||||
" hours";
|
" hours";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +237,7 @@ std::unordered_map<std::string, std::string> getCompleteTitleList() {
|
|||||||
std::unordered_map<std::string, std::string> map;
|
std::unordered_map<std::string, std::string> map;
|
||||||
for (const auto& pair : titles) {
|
for (const auto& pair : titles) {
|
||||||
for (const auto& title : pair.second) {
|
for (const auto& title : pair.second) {
|
||||||
map.emplace(string_utils::format("0x%016llX", title.id()), title.name());
|
map.emplace(StringUtils::format("0x%016llX", title.id()), title.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
|
|||||||
+15
-15
@@ -14,7 +14,7 @@
|
|||||||
static bool s_notification_led_available = false;
|
static bool s_notification_led_available = false;
|
||||||
|
|
||||||
void servicesExit() {
|
void servicesExit() {
|
||||||
account::exit();
|
Account::exit();
|
||||||
plExit();
|
plExit();
|
||||||
romfsExit();
|
romfsExit();
|
||||||
}
|
}
|
||||||
@@ -37,8 +37,8 @@ Result servicesInit() {
|
|||||||
nxst::log::error("plInitialize failed. Result code 0x%08X.", res);
|
nxst::log::error("plInitialize failed. Result code 0x%08X.", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (R_FAILED(res = account::init())) {
|
if (R_FAILED(res = Account::init())) {
|
||||||
nxst::log::error("account::init failed. Result code 0x%08X.", res);
|
nxst::log::error("Account::init failed. Result code 0x%08X.", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (R_FAILED(res = nsInitialize())) {
|
if (R_FAILED(res = nsInitialize())) {
|
||||||
@@ -55,7 +55,7 @@ Result servicesInit() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_utils::containsInvalidChar(const std::string& str) {
|
bool StringUtils::containsInvalidChar(const std::string& str) {
|
||||||
for (unsigned char c : str) {
|
for (unsigned char c : str) {
|
||||||
if (!isascii(c))
|
if (!isascii(c))
|
||||||
return true;
|
return true;
|
||||||
@@ -63,7 +63,7 @@ bool string_utils::containsInvalidChar(const std::string& str) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_utils::format(const char* fmt, ...) {
|
std::string StringUtils::format(const char* fmt, ...) {
|
||||||
va_list a1, a2;
|
va_list a1, a2;
|
||||||
va_start(a1, fmt);
|
va_start(a1, fmt);
|
||||||
va_copy(a2, a1);
|
va_copy(a2, a1);
|
||||||
@@ -79,7 +79,7 @@ std::string string_utils::format(const char* fmt, ...) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_utils::removeForbiddenCharacters(std::string src) {
|
std::string StringUtils::removeForbiddenCharacters(std::string src) {
|
||||||
static constexpr std::string_view kForbidden = ".,!\\/:?*\"<>|";
|
static constexpr std::string_view kForbidden = ".,!\\/:?*\"<>|";
|
||||||
for (char& c : src) {
|
for (char& c : src) {
|
||||||
if (kForbidden.find(c) != std::string_view::npos)
|
if (kForbidden.find(c) != std::string_view::npos)
|
||||||
@@ -114,7 +114,7 @@ static size_t encodeUtf8(char* out, char32_t cp) {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_utils::UTF16toUTF8(const std::u16string& src) {
|
std::string StringUtils::UTF16toUTF8(const std::u16string& src) {
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(src.size() * 2);
|
result.reserve(src.size() * 2);
|
||||||
for (size_t i = 0; i < src.size(); ++i) {
|
for (size_t i = 0; i < src.size(); ++i) {
|
||||||
@@ -128,13 +128,13 @@ std::string string_utils::UTF16toUTF8(const std::u16string& src) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_utils::ltrim(std::string& s) {
|
void StringUtils::ltrim(std::string& s) {
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c) {
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c) {
|
||||||
return !std::isspace(c);
|
return !std::isspace(c);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_utils::rtrim(std::string& s) {
|
void StringUtils::rtrim(std::string& s) {
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||||
[](unsigned char c) {
|
[](unsigned char c) {
|
||||||
return !std::isspace(c);
|
return !std::isspace(c);
|
||||||
@@ -143,13 +143,13 @@ void string_utils::rtrim(std::string& s) {
|
|||||||
s.end());
|
s.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_utils::trim(std::string& s) {
|
void StringUtils::trim(std::string& s) {
|
||||||
ltrim(s);
|
ltrim(s);
|
||||||
rtrim(s);
|
rtrim(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decodes a UTF-8 string to UTF-16, handling surrogate pairs for codepoints > U+FFFF.
|
// Decodes a UTF-8 string to UTF-16, handling surrogate pairs for codepoints > U+FFFF.
|
||||||
std::u16string string_utils::UTF8toUTF16(const char* src) {
|
std::u16string StringUtils::UTF8toUTF16(const char* src) {
|
||||||
std::u16string result;
|
std::u16string result;
|
||||||
while (*src != '\0') {
|
while (*src != '\0') {
|
||||||
char32_t cp = 0;
|
char32_t cp = 0;
|
||||||
@@ -181,7 +181,7 @@ std::u16string string_utils::UTF8toUTF16(const char* src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replaces Latin characters with diacritics with their ASCII base equivalents.
|
// Replaces Latin characters with diacritics with their ASCII base equivalents.
|
||||||
std::string string_utils::removeAccents(std::string str) {
|
std::string StringUtils::removeAccents(std::string str) {
|
||||||
static const std::unordered_map<char16_t, char16_t> kMap = {
|
static const std::unordered_map<char16_t, char16_t> kMap = {
|
||||||
{u'À', u'A'}, {u'Á', u'A'}, {u'Â', u'A'}, {u'Ã', u'A'}, {u'Ä', u'A'}, {u'Å', u'A'}, {u'Æ', u'E'},
|
{u'À', u'A'}, {u'Á', u'A'}, {u'Â', u'A'}, {u'Ã', u'A'}, {u'Ä', u'A'}, {u'Å', u'A'}, {u'Æ', u'E'},
|
||||||
{u'Ç', u'C'}, {u'È', u'E'}, {u'É', u'E'}, {u'Ê', u'E'}, {u'Ë', u'E'}, {u'Ì', u'I'}, {u'Í', u'I'},
|
{u'Ç', u'C'}, {u'È', u'E'}, {u'É', u'E'}, {u'Ê', u'E'}, {u'Ë', u'E'}, {u'Ì', u'I'}, {u'Í', u'I'},
|
||||||
@@ -199,10 +199,10 @@ std::string string_utils::removeAccents(std::string str) {
|
|||||||
if (it != kMap.end())
|
if (it != kMap.end())
|
||||||
ch = it->second;
|
ch = it->second;
|
||||||
}
|
}
|
||||||
return string_utils::UTF16toUTF8(wide);
|
return StringUtils::UTF16toUTF8(wide);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_utils::removeNotAscii(std::string str) {
|
std::string StringUtils::removeNotAscii(std::string str) {
|
||||||
for (char& c : str) {
|
for (char& c : str) {
|
||||||
if (!isascii(static_cast<unsigned char>(c)))
|
if (!isascii(static_cast<unsigned char>(c)))
|
||||||
c = ' ';
|
c = ' ';
|
||||||
@@ -210,7 +210,7 @@ std::string string_utils::removeNotAscii(std::string str) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string_utils::elide(const std::string& s, size_t max_chars) {
|
std::string StringUtils::elide(const std::string& s, size_t max_chars) {
|
||||||
if (s.size() <= max_chars || max_chars < 6)
|
if (s.size() <= max_chars || max_chars < 6)
|
||||||
return s;
|
return s;
|
||||||
size_t budget = max_chars - 3;
|
size_t budget = max_chars - 3;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// Copyright (C) 2024-2026 NXST contributors
|
// Copyright (C) 2024-2026 NXST contributors
|
||||||
#include <nxst/infra/fs/filesystem.hpp>
|
#include <nxst/infra/fs/filesystem.hpp>
|
||||||
|
|
||||||
Result file_system::mount(FsFileSystem* fs, u64 title_id, AccountUid uid) {
|
Result FileSystem::mount(FsFileSystem* fs, u64 title_id, AccountUid uid) {
|
||||||
return fsOpen_SaveData(fs, title_id, uid);
|
return fsOpen_SaveData(fs, title_id, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_system::mount(FsFileSystem fs) {
|
int FileSystem::mount(FsFileSystem fs) {
|
||||||
return fsdevMountDevice("save", fs);
|
return fsdevMountDevice("save", fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_system::unmount() {
|
void FileSystem::unmount() {
|
||||||
fsdevUnmountDevice("save");
|
fsdevUnmountDevice("save");
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-17
@@ -136,7 +136,7 @@ nxst::Result<std::string> io::backup(size_t index, AccountUid uid) {
|
|||||||
title.id(), title.userId().uid[1], title.userId().uid[0]);
|
title.id(), title.userId().uid[1], title.userId().uid[0]);
|
||||||
|
|
||||||
nxst::FsFileSystemHandle fs_handle;
|
nxst::FsFileSystemHandle fs_handle;
|
||||||
Result res = file_system::mount(fs_handle.get(), title.id(), title.userId());
|
Result res = FileSystem::mount(fs_handle.get(), title.id(), title.userId());
|
||||||
if (R_FAILED(res)) {
|
if (R_FAILED(res)) {
|
||||||
nxst::log::error("Failed to mount filesystem during backup with result 0x%08X. "
|
nxst::log::error("Failed to mount filesystem during backup with result 0x%08X. "
|
||||||
"Title id: 0x%016lX; User id: 0x%lX%lX.",
|
"Title id: 0x%016lX; User id: 0x%lX%lX.",
|
||||||
@@ -145,16 +145,16 @@ nxst::Result<std::string> io::backup(size_t index, AccountUid uid) {
|
|||||||
}
|
}
|
||||||
fs_handle.valid = true;
|
fs_handle.valid = true;
|
||||||
|
|
||||||
if (file_system::mount(*fs_handle.get()) == -1) {
|
if (FileSystem::mount(*fs_handle.get()) == -1) {
|
||||||
nxst::log::error("Failed to mount devfs during backup. Title id: 0x%016lX; User id: 0x%lX%lX.",
|
nxst::log::error("Failed to mount devfs during backup. Title id: 0x%016lX; User id: 0x%lX%lX.",
|
||||||
title.id(), title.userId().uid[1], title.userId().uid[0]);
|
title.id(), title.userId().uid[1], title.userId().uid[0]);
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
return nxst::Result<std::string>::failure("Failed to mount save.");
|
return nxst::Result<std::string>::failure("Failed to mount save.");
|
||||||
}
|
}
|
||||||
fs_handle.release(); // devfs now owns the kernel handle
|
fs_handle.release(); // devfs now owns the kernel handle
|
||||||
|
|
||||||
std::string suggestion =
|
std::string suggestion =
|
||||||
string_utils::removeNotAscii(string_utils::removeAccents(account::username(title.userId())));
|
StringUtils::removeNotAscii(StringUtils::removeAccents(Account::username(title.userId())));
|
||||||
|
|
||||||
io::createDirectory(title.path());
|
io::createDirectory(title.path());
|
||||||
std::string dst_path = title.path() + "/" + suggestion;
|
std::string dst_path = title.path() + "/" + suggestion;
|
||||||
@@ -166,13 +166,13 @@ nxst::Result<std::string> io::backup(size_t index, AccountUid uid) {
|
|||||||
}
|
}
|
||||||
res = io::createDirectory(tmp_path);
|
res = io::createDirectory(tmp_path);
|
||||||
if (R_FAILED(res)) {
|
if (R_FAILED(res)) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
nxst::log::error("Failed to create tmp dir %s.", tmp_path.c_str());
|
nxst::log::error("Failed to create tmp dir %s.", tmp_path.c_str());
|
||||||
return nxst::Result<std::string>::failure("Failed to create tmp directory.");
|
return nxst::Result<std::string>::failure("Failed to create tmp directory.");
|
||||||
}
|
}
|
||||||
res = copyDirectory("save:/", tmp_path + "/");
|
res = copyDirectory("save:/", tmp_path + "/");
|
||||||
if (R_FAILED(res)) {
|
if (R_FAILED(res)) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
io::deleteFolderRecursively(tmp_path + "/");
|
io::deleteFolderRecursively(tmp_path + "/");
|
||||||
nxst::log::error("Failed to copy directory to %s with result 0x%08X.", tmp_path.c_str(), res);
|
nxst::log::error("Failed to copy directory to %s with result 0x%08X.", tmp_path.c_str(), res);
|
||||||
return nxst::Result<std::string>::failure("Failed to backup save.");
|
return nxst::Result<std::string>::failure("Failed to backup save.");
|
||||||
@@ -183,13 +183,13 @@ nxst::Result<std::string> io::backup(size_t index, AccountUid uid) {
|
|||||||
nxst::log::warn("Failed to remove old backup at %s.", dst_path.c_str());
|
nxst::log::warn("Failed to remove old backup at %s.", dst_path.c_str());
|
||||||
}
|
}
|
||||||
if (rename(tmp_path.c_str(), dst_path.c_str()) != 0) {
|
if (rename(tmp_path.c_str(), dst_path.c_str()) != 0) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
nxst::log::error("Failed to rename temp backup to %s.", dst_path.c_str());
|
nxst::log::error("Failed to rename temp backup to %s.", dst_path.c_str());
|
||||||
return nxst::Result<std::string>::failure("Failed to finalise backup.");
|
return nxst::Result<std::string>::failure("Failed to finalise backup.");
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshDirectories(title.id());
|
refreshDirectories(title.id());
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
|
|
||||||
nxst::log::info("Backup succeeded.");
|
nxst::log::info("Backup succeeded.");
|
||||||
return nxst::Result<std::string>::success(dst_path);
|
return nxst::Result<std::string>::success(dst_path);
|
||||||
@@ -268,7 +268,7 @@ nxst::Result<std::string> io::restore(size_t index, AccountUid uid, const std::s
|
|||||||
createSaveIfNeeded(title.id(), uid);
|
createSaveIfNeeded(title.id(), uid);
|
||||||
|
|
||||||
nxst::FsFileSystemHandle fs_handle;
|
nxst::FsFileSystemHandle fs_handle;
|
||||||
Result res = file_system::mount(fs_handle.get(), title.id(), uid);
|
Result res = FileSystem::mount(fs_handle.get(), title.id(), uid);
|
||||||
if (R_FAILED(res)) {
|
if (R_FAILED(res)) {
|
||||||
nxst::log::error("Failed to mount filesystem during restore with result 0x%08X. "
|
nxst::log::error("Failed to mount filesystem during restore with result 0x%08X. "
|
||||||
"Title id: 0x%016lX; User id: 0x%lX%lX.",
|
"Title id: 0x%016lX; User id: 0x%lX%lX.",
|
||||||
@@ -277,23 +277,22 @@ nxst::Result<std::string> io::restore(size_t index, AccountUid uid, const std::s
|
|||||||
}
|
}
|
||||||
fs_handle.valid = true;
|
fs_handle.valid = true;
|
||||||
|
|
||||||
if (file_system::mount(*fs_handle.get()) == -1) {
|
if (FileSystem::mount(*fs_handle.get()) == -1) {
|
||||||
nxst::log::error("Failed to mount devfs during restore. Title id: 0x%016lX; User id: 0x%lX%lX.",
|
nxst::log::error("Failed to mount devfs during restore. Title id: 0x%016lX; User id: 0x%lX%lX.",
|
||||||
title.id(), uid.uid[1], uid.uid[0]);
|
title.id(), uid.uid[1], uid.uid[0]);
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
return nxst::Result<std::string>::failure("Failed to mount save.");
|
return nxst::Result<std::string>::failure("Failed to mount save.");
|
||||||
}
|
}
|
||||||
fs_handle.release(); // devfs now owns the kernel handle
|
fs_handle.release(); // devfs now owns the kernel handle
|
||||||
|
|
||||||
std::string suggestion =
|
std::string suggestion = StringUtils::removeNotAscii(StringUtils::removeAccents(Account::username(uid)));
|
||||||
string_utils::removeNotAscii(string_utils::removeAccents(account::username(uid)));
|
|
||||||
std::string src_path = title.path() + "/" + suggestion + "/";
|
std::string src_path = title.path() + "/" + suggestion + "/";
|
||||||
const std::string dst_path = "save:/";
|
const std::string dst_path = "save:/";
|
||||||
|
|
||||||
{
|
{
|
||||||
Directory src_check(src_path);
|
Directory src_check(src_path);
|
||||||
if (!src_check.good() || src_check.size() == 0) {
|
if (!src_check.good() || src_check.size() == 0) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
nxst::log::error("Restore source is empty or missing: %s", src_path.c_str());
|
nxst::log::error("Restore source is empty or missing: %s", src_path.c_str());
|
||||||
return nxst::Result<std::string>::failure("Restore source is empty or missing.");
|
return nxst::Result<std::string>::failure("Restore source is empty or missing.");
|
||||||
}
|
}
|
||||||
@@ -301,18 +300,18 @@ nxst::Result<std::string> io::restore(size_t index, AccountUid uid, const std::s
|
|||||||
|
|
||||||
auto clear_res = clearSaveRoot(dst_path);
|
auto clear_res = clearSaveRoot(dst_path);
|
||||||
if (!clear_res.isOk()) {
|
if (!clear_res.isOk()) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
return nxst::Result<std::string>::failure(clear_res.error());
|
return nxst::Result<std::string>::failure(clear_res.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto extract_res = extractAndCommit(src_path, dst_path);
|
auto extract_res = extractAndCommit(src_path, dst_path);
|
||||||
if (!extract_res.isOk()) {
|
if (!extract_res.isOk()) {
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
return nxst::Result<std::string>::failure(extract_res.error());
|
return nxst::Result<std::string>::failure(extract_res.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
blinkLed(4);
|
blinkLed(4);
|
||||||
file_system::unmount();
|
FileSystem::unmount();
|
||||||
|
|
||||||
nxst::log::info("Restore succeeded.");
|
nxst::log::info("Restore succeeded.");
|
||||||
return nxst::Result<std::string>::success(title_name + "\nhas been restored successfully.");
|
return nxst::Result<std::string>::success(title_name + "\nhas been restored successfully.");
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ namespace nxst {
|
|||||||
std::string TransferService::replaceUsername(const std::string& file_path) const {
|
std::string TransferService::replaceUsername(const std::string& file_path) const {
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
std::string username =
|
std::string username =
|
||||||
string_utils::removeNotAscii(string_utils::removeAccents(account::username(restore_uid)));
|
StringUtils::removeNotAscii(StringUtils::removeAccents(Account::username(restore_uid)));
|
||||||
size_t last_slash = file_path.rfind('/');
|
size_t last_slash = file_path.rfind('/');
|
||||||
if (last_slash == std::string::npos)
|
if (last_slash == std::string::npos)
|
||||||
return file_path;
|
return file_path;
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ namespace ui {
|
|||||||
this->refreshButtons();
|
this->refreshButtons();
|
||||||
this->updateHints();
|
this->updateHints();
|
||||||
|
|
||||||
this->header->SetUser(uid, account::username(uid));
|
this->header->SetUser(uid, Account::username(uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitlesLayout::refreshPanel() {
|
void TitlesLayout::refreshPanel() {
|
||||||
@@ -144,7 +144,7 @@ namespace ui {
|
|||||||
int idx = this->titlesMenu->GetSelectedIndex();
|
int idx = this->titlesMenu->GetSelectedIndex();
|
||||||
Title title;
|
Title title;
|
||||||
getTitle(title, this->current_uid, idx);
|
getTitle(title, this->current_uid, idx);
|
||||||
this->panelTitle->SetText(string_utils::elide(title.name(), 24));
|
this->panelTitle->SetText(StringUtils::elide(title.name(), 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitlesLayout::refreshButtons() {
|
void TitlesLayout::refreshButtons() {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ namespace ui {
|
|||||||
this->usersMenu->SetScrollbarColor(color::Primary);
|
this->usersMenu->SetScrollbarColor(color::Primary);
|
||||||
this->usersMenu->SetItemsFocusColor(color::BgSurface2);
|
this->usersMenu->SetItemsFocusColor(color::BgSurface2);
|
||||||
|
|
||||||
for (AccountUid const& uid : account::ids()) {
|
for (AccountUid const& uid : Account::ids()) {
|
||||||
auto item = pu::ui::elm::MenuItem::New(account::username(uid));
|
auto item = pu::ui::elm::MenuItem::New(Account::username(uid));
|
||||||
item->SetColor(color::TextPrimary);
|
item->SetColor(color::TextPrimary);
|
||||||
this->usersMenu->AddItem(item);
|
this->usersMenu->AddItem(item);
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ namespace ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Down & HidNpadButton_A) {
|
if (Down & HidNpadButton_A) {
|
||||||
AccountUid uid = account::ids().at(this->usersMenu->GetSelectedIndex());
|
AccountUid uid = Account::ids().at(this->usersMenu->GetSelectedIndex());
|
||||||
|
|
||||||
if (!areTitlesLoaded()) {
|
if (!areTitlesLoaded()) {
|
||||||
this->usersMenu->SetVisible(false);
|
this->usersMenu->SetVisible(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user