replace progress box result from bool to Result. Display error box if progress box fails.
This commit is contained in:
@@ -61,6 +61,9 @@ public:
|
||||
static void NotifyClear(ui::NotifEntry::Side side = ui::NotifEntry::Side::RIGHT);
|
||||
static void NotifyFlashLed();
|
||||
|
||||
// if R_FAILED(rc), pushes error box. returns rc passed in.
|
||||
static Result PushErrorBox(Result rc, const std::string& message);
|
||||
|
||||
static auto GetThemeMetaList() -> std::span<ThemeMeta>;
|
||||
static void SetTheme(s64 theme_index);
|
||||
static auto GetThemeIndex() -> s64;
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
namespace sphaira::ui {
|
||||
|
||||
struct ProgressBox;
|
||||
using ProgressBoxCallback = std::function<bool(ProgressBox*)>;
|
||||
using ProgressBoxDoneCallback = std::function<void(bool success)>;
|
||||
using ProgressBoxCallback = std::function<Result(ProgressBox*)>;
|
||||
using ProgressBoxDoneCallback = std::function<void(Result rc)>;
|
||||
|
||||
struct ProgressBox final : Widget {
|
||||
ProgressBox(
|
||||
int image,
|
||||
const std::string& action,
|
||||
const std::string& title,
|
||||
ProgressBoxCallback callback, ProgressBoxDoneCallback done = [](bool success){},
|
||||
ProgressBoxCallback callback, ProgressBoxDoneCallback done = [](Result rc){},
|
||||
int cpuid = 1, int prio = 0x2C, int stack_size = 1024*128
|
||||
);
|
||||
~ProgressBox();
|
||||
@@ -30,8 +30,10 @@ struct ProgressBox final : Widget {
|
||||
// not const in order to avoid copy by using std::swap
|
||||
auto SetImageData(std::vector<u8>& data) -> ProgressBox&;
|
||||
auto SetImageDataConst(std::span<const u8> data) -> ProgressBox&;
|
||||
|
||||
void RequestExit();
|
||||
auto ShouldExit() -> bool;
|
||||
auto ShouldExitResult() -> Result;
|
||||
|
||||
// helper functions
|
||||
auto CopyFile(const fs::FsPath& src, const fs::FsPath& dst) -> Result;
|
||||
@@ -64,7 +66,7 @@ public:
|
||||
struct ThreadData {
|
||||
ProgressBox* pbox{};
|
||||
ProgressBoxCallback callback{};
|
||||
bool result{};
|
||||
Result result{};
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -50,15 +50,17 @@ void download_default_music() {
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||
);
|
||||
|
||||
return result.success;
|
||||
}, [](bool success){
|
||||
if (success) {
|
||||
if (!result.success) {
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}, [](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Downloaded "_i18n + "default_music.bfstm");
|
||||
App::SetTheme(App::GetThemeIndex());
|
||||
} else {
|
||||
App::Push(std::make_shared<ui::ErrorBox>(
|
||||
"Failed to download default_music.bfstm, please try again"_i18n
|
||||
));
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -568,6 +570,13 @@ void App::NotifyFlashLed() {
|
||||
}
|
||||
}
|
||||
|
||||
Result App::PushErrorBox(Result rc, const std::string& message) {
|
||||
if (R_FAILED(rc)) {
|
||||
App::Push(std::make_shared<ui::ErrorBox>(rc, message));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
auto App::GetThemeMetaList() -> std::span<ThemeMeta> {
|
||||
return g_app->m_theme_meta_entries;
|
||||
}
|
||||
@@ -742,9 +751,10 @@ void App::SetReplaceHbmenuEnable(bool enable) {
|
||||
if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", "/switch/hbmenu.nro"))) {
|
||||
// try and restore sphaira in a last ditch effort.
|
||||
if (R_FAILED(rc = fs.copy_entire_file("/hbmenu.nro", sphaira_path))) {
|
||||
App::Push(std::make_shared<ui::ErrorBox>(rc,
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
App::PushErrorBox(rc,
|
||||
"Failed to restore hbmenu, please re-download hbmenu"_i18n
|
||||
));
|
||||
);
|
||||
} else {
|
||||
App::Push(std::make_shared<ui::OptionBox>(
|
||||
"Failed to restore hbmenu, using sphaira instead"_i18n,
|
||||
|
||||
@@ -1012,8 +1012,8 @@ auto install_forwarder(ui::ProgressBox* pbox, OwoConfig& config, NcmStorageId st
|
||||
}
|
||||
|
||||
auto install_forwarder(OwoConfig& config, NcmStorageId storage_id) -> Result {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing Forwarder"_i18n, config.name, [config, storage_id](auto pbox) mutable -> bool {
|
||||
return R_SUCCEEDED(install_forwarder(pbox, config, storage_id));
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing Forwarder"_i18n, config.name, [config, storage_id](auto pbox) mutable -> Result {
|
||||
return install_forwarder(pbox, config, storage_id);
|
||||
}));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -286,14 +286,12 @@ void ReadFromInfoJson(Entry& e) {
|
||||
|
||||
// this ignores ShouldExit() as leaving somthing in a half
|
||||
// deleted state is a bad idea :)
|
||||
auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
||||
const auto manifest = LoadAndParseManifest(entry);
|
||||
fs::FsNativeSd fs;
|
||||
|
||||
if (manifest.empty()) {
|
||||
if (entry.binary.empty()) {
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(!entry.binary.empty(), 0x1);
|
||||
fs.DeleteFile(entry.binary);
|
||||
} else {
|
||||
for (auto& e : manifest) {
|
||||
@@ -319,7 +317,8 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
} else {
|
||||
log_write("deleted: %s\n", dir.s);
|
||||
}
|
||||
return true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// this is called by ProgressBox on a seperate thread
|
||||
@@ -328,12 +327,12 @@ auto UninstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
// 2. md5 check the zip
|
||||
// 3. parse manifest and unzip everything to placeholder
|
||||
// 4. move everything from placeholder to normal location
|
||||
auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
auto InstallApp(ProgressBox* pbox, const Entry& entry) -> Result {
|
||||
static const fs::FsPath zip_out{"/switch/sphaira/cache/appstore/temp.zip"};
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
|
||||
fs::FsNativeSd fs;
|
||||
R_TRY_RESULT(fs.GetFsOpenResult(), false);
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
|
||||
// 1. download the zip
|
||||
if (!pbox->ShouldExit()) {
|
||||
@@ -341,14 +340,13 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
log_write("starting download\n");
|
||||
|
||||
const auto url = BuildZipUrl(entry);
|
||||
if (!curl::Api().ToFile(
|
||||
const auto result = curl::Api().ToFile(
|
||||
curl::Url{url},
|
||||
curl::Path{zip_out},
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||
).success) {
|
||||
log_write("error with download\n");
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
R_UNLESS(result.success, 0x1);
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
|
||||
@@ -359,15 +357,11 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
log_write("starting md5 check\n");
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(fs.OpenFile(zip_out, FsOpenMode_Read, &f))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(zip_out, FsOpenMode_Read, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
s64 size;
|
||||
if (R_FAILED(fsFileGetSize(&f, &size))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileGetSize(&f, &size));
|
||||
|
||||
mbedtls_md5_context ctx;
|
||||
mbedtls_md5_init(&ctx);
|
||||
@@ -380,19 +374,14 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
std::vector<u8> chunk(chunk_size);
|
||||
s64 offset{};
|
||||
while (offset < size) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
u64 bytes_read;
|
||||
if (R_FAILED(fsFileRead(&f, offset, chunk.data(), chunk.size(), 0, &bytes_read))) {
|
||||
log_write("failed to read file offset: %zd size: %zd\n", offset, size);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileRead(&f, offset, chunk.data(), chunk.size(), 0, &bytes_read));
|
||||
|
||||
if (mbedtls_md5_update_ret(&ctx, chunk.data(), bytes_read)) {
|
||||
log_write("failed to update ret\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
offset += bytes_read;
|
||||
@@ -401,7 +390,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
|
||||
u8 md5_out[16];
|
||||
if (mbedtls_md5_finish_ret(&ctx, (u8*)md5_out)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
// convert md5 to hex string
|
||||
@@ -412,23 +401,20 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
|
||||
if (strncasecmp(md5_str, entry.md5.data(), entry.md5.length())) {
|
||||
log_write("bad md5: %.*s vs %.*s\n", 32, md5_str, 32, entry.md5.c_str());
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. extract the zip
|
||||
if (!pbox->ShouldExit()) {
|
||||
auto zfile = unzOpen64(zip_out);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", zip_out.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
|
||||
// get manifest
|
||||
if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, "manifest.install", 0)) {
|
||||
log_write("failed to find manifest.install\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
ManifestEntries new_manifest;
|
||||
@@ -436,47 +422,47 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
{
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
unz_file_info64 info;
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
std::vector<char> manifest_data(info.uncompressed_size);
|
||||
if ((int)info.uncompressed_size != unzReadCurrentFile(zfile, manifest_data.data(), manifest_data.size())) {
|
||||
log_write("failed to read manifest file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
new_manifest = ParseManifest(manifest_data);
|
||||
if (new_manifest.empty()) {
|
||||
log_write("manifest is empty!\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
const auto unzip_to = [pbox, &fs, zfile](const fs::FsPath& inzip, fs::FsPath output) -> bool {
|
||||
const auto unzip_to = [pbox, &fs, zfile](const fs::FsPath& inzip, fs::FsPath output) -> Result {
|
||||
pbox->NewTransfer(inzip);
|
||||
|
||||
if (UNZ_END_OF_LIST_OF_FILE == unzLocateFile(zfile, inzip, 0)) {
|
||||
log_write("failed to find %s\n", inzip.s);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
unz_file_info64 info;
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, 0, 0, 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (output[0] != '/') {
|
||||
@@ -489,58 +475,41 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
Result rc;
|
||||
if (R_FAILED(rc = fs.CreateFile(output, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create file: %s 0x%04X\n", output.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(rc = fs.OpenFile(output, FsOpenMode_Write, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", output.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(output, FsOpenMode_Write, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) {
|
||||
log_write("failed to set file size: %s 0x%04X\n", output.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileSetSize(&f, info.uncompressed_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
u64 offset{};
|
||||
while (offset < info.uncompressed_size) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
||||
if (bytes_read <= 0) {
|
||||
log_write("failed to read zip file: %s\n", inzip.s);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", output.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
|
||||
|
||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
||||
offset += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
// unzip manifest and info
|
||||
if (!unzip_to("info.json", BuildInfoCachePath(entry))) {
|
||||
return false;
|
||||
}
|
||||
if (!unzip_to("manifest.install", BuildManifestCachePath(entry))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(unzip_to("info.json", BuildInfoCachePath(entry)));
|
||||
R_TRY(unzip_to("manifest.install", BuildManifestCachePath(entry)));
|
||||
|
||||
for (auto& new_entry : new_manifest) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
switch (new_entry.command) {
|
||||
case 'E': // both are the same?
|
||||
@@ -586,7 +555,7 @@ auto InstallApp(ProgressBox* pbox, const Entry& entry) -> bool {
|
||||
}
|
||||
|
||||
log_write("finished install :)\n");
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// case-insensitive version of str.find()
|
||||
@@ -775,27 +744,31 @@ void EntryMenu::UpdateOptions() {
|
||||
const auto install = [this](){
|
||||
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Downloading "_i18n, m_entry.title, [this](auto pbox){
|
||||
return InstallApp(pbox, m_entry);
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Downloaded "_i18n + m_entry.title);
|
||||
m_entry.status = EntryStatus::Installed;
|
||||
m_menu.SetDirty();
|
||||
UpdateOptions();
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
};
|
||||
|
||||
const auto uninstall = [this](){
|
||||
App::Push(std::make_shared<ProgressBox>(m_entry.image.image, "Uninstalling "_i18n, m_entry.title, [this](auto pbox){
|
||||
return UninstallApp(pbox, m_entry);
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Removed "_i18n + m_entry.title);
|
||||
m_entry.status = EntryStatus::Get;
|
||||
m_menu.SetDirty();
|
||||
UpdateOptions();
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
};
|
||||
|
||||
const Option install_option{"Install"_i18n, install};
|
||||
|
||||
@@ -489,7 +489,7 @@ Menu::Menu(const std::vector<NroEntry>& nro_entries) : MenuBase{"FileBrowser"_i1
|
||||
Scan(m_path);
|
||||
} else {
|
||||
const auto msg = std::string("Failed to rename file: ") + entry.name;
|
||||
App::Push(std::make_shared<ErrorBox>(rc, msg.c_str()));
|
||||
App::PushErrorBox(rc, msg);
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -854,15 +854,13 @@ void Menu::InstallForwarder() {
|
||||
if (op_index) {
|
||||
const auto assoc = assoc_list[*op_index];
|
||||
log_write("pushing it\n");
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Installing Forwarder"_i18n, GetEntry().name, [assoc, this](auto pbox) -> bool {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Installing Forwarder"_i18n, GetEntry().name, [assoc, this](auto pbox) -> Result {
|
||||
log_write("inside callback\n");
|
||||
|
||||
NroEntry nro{};
|
||||
log_write("parsing nro\n");
|
||||
if (R_FAILED(nro_parse(assoc.path, nro))) {
|
||||
log_write("failed nro parse\n");
|
||||
return false;
|
||||
}
|
||||
R_TRY(nro_parse(assoc.path, nro));
|
||||
|
||||
log_write("got nro data\n");
|
||||
auto file_name = assoc.use_base_name ? GetEntry().GetName() : GetEntry().GetInternalName();
|
||||
|
||||
@@ -883,7 +881,7 @@ void Menu::InstallForwarder() {
|
||||
config.icon = GetRomIcon(m_fs.get(), pbox, file_name, db_indexs, nro);
|
||||
pbox->SetImageDataConst(config.icon);
|
||||
|
||||
return R_SUCCEEDED(App::Install(pbox, config));
|
||||
return App::Install(pbox, config);
|
||||
}));
|
||||
} else {
|
||||
log_write("pressed B to skip launch...\n");
|
||||
@@ -899,19 +897,13 @@ void Menu::InstallFiles() {
|
||||
if (op_index && *op_index) {
|
||||
App::PopToMenu();
|
||||
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this, targets](auto pbox) -> Result {
|
||||
for (auto& e : targets) {
|
||||
const auto rc = yati::InstallFromFile(pbox, &m_fs->m_fs, GetNewPath(e));
|
||||
if (rc == yati::Result_Cancelled) {
|
||||
break;
|
||||
} else if (R_FAILED(rc)) {
|
||||
return false;
|
||||
} else {
|
||||
R_TRY(yati::InstallFromFile(pbox, &m_fs->m_fs, GetNewPath(e)));
|
||||
App::Notify("Installed " + e.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
}));
|
||||
}
|
||||
}));
|
||||
@@ -925,7 +917,7 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
|
||||
dir_path = m_path;
|
||||
}
|
||||
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Extracting "_i18n, "", [this, dir_path, targets](auto pbox) -> Result {
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
auto& fs = *m_fs.get();
|
||||
|
||||
@@ -934,28 +926,25 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
|
||||
|
||||
const auto zip_out = GetNewPath(e);
|
||||
auto zfile = unzOpen64(zip_out);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", zip_out.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
|
||||
unz_global_info64 pglobal_info;
|
||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
||||
if (i > 0) {
|
||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
||||
log_write("failed to unzGoToNextFile\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
@@ -963,7 +952,7 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
|
||||
char name[512];
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
const auto file_path = fs::AppendPath(dir_path, name);
|
||||
@@ -975,38 +964,27 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
|
||||
Result rc;
|
||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) {
|
||||
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileSetSize(&f, info.uncompressed_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
s64 offset{};
|
||||
while (offset < info.uncompressed_size) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
||||
if (bytes_read <= 0) {
|
||||
log_write("failed to read zip file: %s\n", name);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
|
||||
|
||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
||||
offset += bytes_read;
|
||||
@@ -1014,13 +992,14 @@ void Menu::UnzipFiles(fs::FsPath dir_path) {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Extract success!");
|
||||
} else {
|
||||
App::Notify("Extract failed!");
|
||||
}
|
||||
|
||||
Scan(m_path);
|
||||
log_write("did extract\n");
|
||||
}));
|
||||
@@ -1062,7 +1041,7 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
|
||||
}
|
||||
}
|
||||
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Compressing "_i18n, "", [this, zip_out, targets](auto pbox) -> Result {
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
auto& fs = *m_fs.get();
|
||||
|
||||
@@ -1079,13 +1058,10 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
|
||||
zip_info.tmz_date.tm_year = tm->tm_year;
|
||||
|
||||
auto zfile = zipOpen(zip_out, APPEND_STATUS_CREATE);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", zip_out.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(zipClose(zfile, "sphaira v" APP_VERSION_HASH));
|
||||
|
||||
const auto zip_add = [&](const fs::FsPath& file_path){
|
||||
const auto zip_add = [&](const fs::FsPath& file_path) -> Result {
|
||||
// the file name needs to be relative to the current directory.
|
||||
const char* file_name_in_zip = file_path.s + std::strlen(m_path);
|
||||
|
||||
@@ -1100,56 +1076,42 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
|
||||
const auto raw = ext && IsExtension(ext + 1, COMPRESSED_EXTENSIONS);
|
||||
|
||||
if (ZIP_OK != zipOpenNewFileInZip2(zfile, file_name_in_zip, &zip_info, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, raw)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(zipCloseFileInZip(zfile));
|
||||
|
||||
FsFile f;
|
||||
Result rc;
|
||||
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Read, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Read, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
s64 file_size;
|
||||
if (R_FAILED(rc = fsFileGetSize(&f, &file_size))) {
|
||||
log_write("failed to get file size: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileGetSize(&f, &file_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
s64 offset{};
|
||||
while (offset < file_size) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
u64 bytes_read;
|
||||
if (R_FAILED(rc = fsFileRead(&f, offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileRead(&f, offset, buf.data(), buf.size(), FsReadOption_None, &bytes_read));
|
||||
|
||||
if (ZIP_OK != zipWriteInFileInZip(zfile, buf.data(), bytes_read)) {
|
||||
log_write("failed to write zip file: %s\n", file_path.s);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
pbox->UpdateTransfer(offset, file_size);
|
||||
offset += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
for (auto& e : targets) {
|
||||
pbox->SetTitle(e.GetName());
|
||||
if (e.IsFile()) {
|
||||
const auto file_path = GetNewPath(e);
|
||||
if (!zip_add(file_path)) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(zip_add(file_path));
|
||||
} else {
|
||||
FsDirCollections collections;
|
||||
get_collections(GetNewPath(e), e.name, collections);
|
||||
@@ -1157,21 +1119,20 @@ void Menu::ZipFiles(fs::FsPath zip_out) {
|
||||
for (const auto& collection : collections) {
|
||||
for (const auto& file : collection.files) {
|
||||
const auto file_path = fs::AppendPath(collection.path, file.name);
|
||||
if (!zip_add(file_path)) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(zip_add(file_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Compress success!");
|
||||
} else {
|
||||
App::Notify("Compress failed!");
|
||||
}
|
||||
|
||||
Scan(m_path);
|
||||
log_write("did compress\n");
|
||||
}));
|
||||
@@ -1198,7 +1159,7 @@ void Menu::UploadFiles() {
|
||||
}
|
||||
|
||||
const auto loc = network_locations[*op_index];
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Uploading"_i18n, "", [this, loc](auto pbox) -> bool {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Uploading"_i18n, "", [this, loc](auto pbox) -> Result {
|
||||
auto targets = GetSelectedEntries();
|
||||
|
||||
const auto file_add = [&](s64 file_size, const fs::FsPath& file_path, const char* name) -> Result {
|
||||
@@ -1250,9 +1211,7 @@ void Menu::UploadFiles() {
|
||||
for (auto& e : targets) {
|
||||
if (e.IsFile()) {
|
||||
const auto file_path = GetNewPath(e);
|
||||
if (R_FAILED(file_add(e.file_size, file_path, e.GetName().c_str()))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(file_add(e.file_size, file_path, e.GetName().c_str()));
|
||||
} else {
|
||||
FsDirCollections collections;
|
||||
get_collections(GetNewPath(e), e.name, collections, true);
|
||||
@@ -1260,24 +1219,20 @@ void Menu::UploadFiles() {
|
||||
for (const auto& collection : collections) {
|
||||
for (const auto& file : collection.files) {
|
||||
const auto file_path = fs::AppendPath(collection.path, file.name);
|
||||
if (R_FAILED(file_add(file.file_size, file_path, file.name))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(file_add(file.file_size, file_path, file.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
ResetSelection();
|
||||
|
||||
if (success) {
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Upload successfull!");
|
||||
log_write("Upload successfull!!!\n");
|
||||
} else {
|
||||
App::Notify("Upload failed!");
|
||||
log_write("Upload failed!!!\n");
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -1643,80 +1598,70 @@ void Menu::OnDeleteCallback() {
|
||||
Scan(m_path);
|
||||
log_write("did delete\n");
|
||||
} else {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> Result {
|
||||
FsDirCollections collections;
|
||||
|
||||
// build list of dirs / files
|
||||
for (const auto&p : m_selected_files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto full_path = GetNewPath(m_selected_path, p.name);
|
||||
if (p.IsDir()) {
|
||||
pbox->NewTransfer("Scanning "_i18n + full_path);
|
||||
if (R_FAILED(get_collections(full_path, p.name, collections))) {
|
||||
log_write("failed to get dir collection: %s\n", full_path.s);
|
||||
return false;
|
||||
}
|
||||
R_TRY(get_collections(full_path, p.name, collections));
|
||||
}
|
||||
}
|
||||
|
||||
// delete everything in collections, reversed
|
||||
for (const auto& c : std::views::reverse(collections)) {
|
||||
const auto delete_func = [&](auto& array) {
|
||||
const auto delete_func = [&](auto& array) -> Result {
|
||||
for (const auto& p : array) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto full_path = GetNewPath(c.path, p.name);
|
||||
pbox->NewTransfer("Deleting "_i18n + full_path);
|
||||
if (p.type == FsDirEntryType_Dir) {
|
||||
log_write("deleting dir: %s\n", full_path.s);
|
||||
m_fs->DeleteDirectory(full_path);
|
||||
R_TRY(m_fs->DeleteDirectory(full_path));
|
||||
} else {
|
||||
log_write("deleting file: %s\n", full_path.s);
|
||||
m_fs->DeleteFile(full_path);
|
||||
R_TRY(m_fs->DeleteFile(full_path));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
if (!delete_func(c.files)) {
|
||||
return false;
|
||||
}
|
||||
if (!delete_func(c.dirs)) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(delete_func(c.files));
|
||||
R_TRY(delete_func(c.dirs));
|
||||
}
|
||||
|
||||
for (const auto& p : m_selected_files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto full_path = GetNewPath(m_selected_path, p.name);
|
||||
pbox->NewTransfer("Deleting "_i18n + full_path);
|
||||
|
||||
if (p.IsDir()) {
|
||||
log_write("deleting dir: %s\n", full_path.s);
|
||||
m_fs->DeleteDirectory(full_path);
|
||||
R_TRY(m_fs->DeleteDirectory(full_path));
|
||||
} else {
|
||||
log_write("deleting file: %s\n", full_path.s);
|
||||
m_fs->DeleteFile(full_path);
|
||||
R_TRY(m_fs->DeleteFile(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
ResetSelection();
|
||||
Scan(m_path);
|
||||
log_write("did delete\n");
|
||||
}, 2));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1736,14 +1681,12 @@ void Menu::OnPasteCallback() {
|
||||
Scan(m_path);
|
||||
log_write("did paste\n");
|
||||
} else {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Pasting"_i18n, "", [this](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Pasting"_i18n, "", [this](auto pbox) -> Result {
|
||||
|
||||
if (m_selected_type == SelectedType::Cut) {
|
||||
for (const auto& p : m_selected_files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto src_path = GetNewPath(m_selected_path, p.name);
|
||||
const auto dst_path = GetNewPath(m_path, p.name);
|
||||
@@ -1762,25 +1705,18 @@ void Menu::OnPasteCallback() {
|
||||
// build list of dirs / files
|
||||
for (const auto&p : m_selected_files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto full_path = GetNewPath(m_selected_path, p.name);
|
||||
if (p.IsDir()) {
|
||||
pbox->NewTransfer("Scanning "_i18n + full_path);
|
||||
if (R_FAILED(get_collections(full_path, p.name, collections))) {
|
||||
log_write("failed to get dir collection: %s\n", full_path.s);
|
||||
return false;
|
||||
}
|
||||
R_TRY(get_collections(full_path, p.name, collections));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& p : m_selected_files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto src_path = GetNewPath(m_selected_path, p.name);
|
||||
const auto dst_path = GetNewPath(p);
|
||||
@@ -1790,7 +1726,7 @@ void Menu::OnPasteCallback() {
|
||||
m_fs->CreateDirectory(dst_path);
|
||||
} else {
|
||||
pbox->NewTransfer("Copying "_i18n + src_path);
|
||||
R_TRY_RESULT(pbox->CopyFile(src_path, dst_path), false);
|
||||
R_TRY(pbox->CopyFile(src_path, dst_path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1800,9 +1736,7 @@ void Menu::OnPasteCallback() {
|
||||
|
||||
for (const auto& p : c.dirs) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto src_path = GetNewPath(c.path, p.name);
|
||||
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
||||
@@ -1814,26 +1748,26 @@ void Menu::OnPasteCallback() {
|
||||
|
||||
for (const auto& p : c.files) {
|
||||
pbox->Yield();
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto src_path = GetNewPath(c.path, p.name);
|
||||
const auto dst_path = GetNewPath(base_dst_path, p.name);
|
||||
|
||||
pbox->NewTransfer("Copying "_i18n + src_path);
|
||||
log_write("copying: %s to %s\n", src_path.s, dst_path.s);
|
||||
R_TRY_RESULT(pbox->CopyFile(src_path, dst_path), false);
|
||||
R_TRY(pbox->CopyFile(src_path, dst_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to, TODO: add message here"_i18n);
|
||||
|
||||
ResetSelection();
|
||||
Scan(m_path);
|
||||
log_write("did paste\n");
|
||||
}, 2));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,25 +202,25 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||
log_write("set to progress\n");
|
||||
m_state = State::Progress;
|
||||
log_write("got connection\n");
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) -> Result {
|
||||
log_write("inside progress box\n");
|
||||
const auto rc = yati::InstallFromSource(pbox, m_source, m_source->m_path);
|
||||
if (R_FAILED(rc)) {
|
||||
m_source->Disable();
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
log_write("progress box is done\n");
|
||||
return true;
|
||||
}, [this](bool result){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Ftp install failed!"_i18n);
|
||||
|
||||
mutexLock(&m_mutex);
|
||||
ON_SCOPE_EXIT(mutexUnlock(&m_mutex));
|
||||
|
||||
if (result) {
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Ftp install success!"_i18n);
|
||||
m_state = State::Done;
|
||||
} else {
|
||||
App::Notify("Ftp install failed!"_i18n);
|
||||
m_state = State::Failed;
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -1361,7 +1361,7 @@ void Menu::OnLayoutChange() {
|
||||
}
|
||||
|
||||
void Menu::DeleteGames() {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> bool {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Deleting"_i18n, "", [this](auto pbox) -> Result {
|
||||
auto targets = GetSelectedEntries();
|
||||
|
||||
for (s64 i = 0; i < std::size(targets); i++) {
|
||||
@@ -1370,18 +1370,18 @@ void Menu::DeleteGames() {
|
||||
LoadControlEntry(e);
|
||||
pbox->SetTitle(e.GetName());
|
||||
pbox->UpdateTransfer(i + 1, std::size(targets));
|
||||
nsDeleteApplicationCompletely(e.app_id);
|
||||
R_TRY(nsDeleteApplicationCompletely(e.app_id));
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool success){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Delete failed"_i18n);
|
||||
|
||||
ClearSelection();
|
||||
m_dirty = true;
|
||||
|
||||
if (success) {
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Delete successfull!");
|
||||
} else {
|
||||
App::Notify("Delete failed!");
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -1405,7 +1405,7 @@ void Menu::DumpGames(u32 flags) {
|
||||
}
|
||||
|
||||
const auto index = *op_index;
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> bool {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> Result {
|
||||
auto targets = GetSelectedEntries();
|
||||
|
||||
std::vector<NspEntry> nsp_entries;
|
||||
@@ -1416,25 +1416,23 @@ void Menu::DumpGames(u32 flags) {
|
||||
const auto index2 = index - network_locations.size();
|
||||
|
||||
if (!network_locations.empty() && index < network_locations.size()) {
|
||||
return R_SUCCEEDED(DumpNspToNetwork(pbox, network_locations[index], nsp_entries));
|
||||
R_TRY(DumpNspToNetwork(pbox, network_locations[index], nsp_entries));
|
||||
} else if (index2 == DumpLocationType_SdCard) {
|
||||
return R_SUCCEEDED(DumpNspToFile(pbox, nsp_entries));
|
||||
R_TRY(DumpNspToFile(pbox, nsp_entries));
|
||||
} else if (index2 == DumpLocationType_UsbS2S) {
|
||||
return R_SUCCEEDED(DumpNspToUsbS2S(pbox, nsp_entries));
|
||||
R_TRY(DumpNspToUsbS2S(pbox, nsp_entries));
|
||||
} else if (index2 == DumpLocationType_DevNull) {
|
||||
return R_SUCCEEDED(DumpNspToDevNull(pbox, nsp_entries));
|
||||
R_TRY(DumpNspToDevNull(pbox, nsp_entries));
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [this](bool success){
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Dump failed!"_i18n);
|
||||
ClearSelection();
|
||||
|
||||
if (success) {
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Dump successfull!");
|
||||
log_write("dump successfull!!!\n");
|
||||
} else {
|
||||
App::Notify("Dump failed!");
|
||||
log_write("dump failed!!!\n");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -875,14 +875,14 @@ Result Menu::GcMount() {
|
||||
}
|
||||
|
||||
if (m_option_index == 0) {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) -> Result {
|
||||
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
|
||||
return R_SUCCEEDED(yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config));
|
||||
}, [this](bool result){
|
||||
if (result) {
|
||||
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Gc install failed"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Gc install success!"_i18n);
|
||||
} else {
|
||||
App::Notify("Gc install failed!"_i18n);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
@@ -1197,15 +1197,12 @@ void Menu::DumpGames(u32 flags) {
|
||||
}
|
||||
|
||||
const auto index = *op_index;
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> bool {
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Dumping"_i18n, "", [this, network_locations, index, flags](auto pbox) -> Result {
|
||||
XciEntry entry{};
|
||||
entry.menu = this;
|
||||
entry.application_name = m_entries[m_entry_index].lang_entry.name;
|
||||
|
||||
if (R_FAILED(GcMountStorage())) {
|
||||
log_write("failed to mount storage\n");
|
||||
return false;
|
||||
}
|
||||
R_TRY(GcMountStorage());
|
||||
|
||||
std::vector<fs::FsPath> paths;
|
||||
if (flags & DumpFileFlag_XCI) {
|
||||
@@ -1221,9 +1218,7 @@ void Menu::DumpGames(u32 flags) {
|
||||
|
||||
if (flags & DumpFileFlag_Set) {
|
||||
entry.id_set.resize(0xC);
|
||||
if (R_FAILED(fsDeviceOperatorGetGameCardIdSet(&m_dev_op, entry.id_set.data(), entry.id_set.size(), entry.id_set.size()))) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsDeviceOperatorGetGameCardIdSet(&m_dev_op, entry.id_set.data(), entry.id_set.size(), entry.id_set.size()));
|
||||
paths.emplace_back(BuildFullDumpPath(DumpFileType_Set, m_entries));
|
||||
}
|
||||
|
||||
@@ -1235,12 +1230,7 @@ void Menu::DumpGames(u32 flags) {
|
||||
if (flags & DumpFileFlag_Cert) {
|
||||
s64 size;
|
||||
entry.cert.resize(0x200);
|
||||
if (R_FAILED(fsDeviceOperatorGetGameCardDeviceCertificate(&m_dev_op, &m_handle, entry.cert.data(), entry.cert.size(), &size, entry.cert.size()))) {
|
||||
return false;
|
||||
}
|
||||
if (size != entry.cert.size()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsDeviceOperatorGetGameCardDeviceCertificate(&m_dev_op, &m_handle, entry.cert.data(), entry.cert.size(), &size, entry.cert.size()));
|
||||
paths.emplace_back(BuildFullDumpPath(DumpFileType_Cert, m_entries));
|
||||
}
|
||||
|
||||
@@ -1252,23 +1242,22 @@ void Menu::DumpGames(u32 flags) {
|
||||
const auto index2 = index - network_locations.size();
|
||||
|
||||
if (!network_locations.empty() && index < network_locations.size()) {
|
||||
return R_SUCCEEDED(DumpNspToNetwork(pbox, network_locations[index], paths, entry));
|
||||
R_TRY(DumpNspToNetwork(pbox, network_locations[index], paths, entry));
|
||||
} else if (index2 == DumpLocationType_SdCard) {
|
||||
return R_SUCCEEDED(DumpNspToFile(pbox, paths, entry));
|
||||
R_TRY(DumpNspToFile(pbox, paths, entry));
|
||||
} else if (index2 == DumpLocationType_UsbS2S) {
|
||||
return R_SUCCEEDED(DumpNspToUsbS2S(pbox, paths, entry));
|
||||
R_TRY(DumpNspToUsbS2S(pbox, paths, entry));
|
||||
} else if (index2 == DumpLocationType_DevNull) {
|
||||
return R_SUCCEEDED(DumpNspToDevNull(pbox, paths, entry));
|
||||
R_TRY(DumpNspToDevNull(pbox, paths, entry));
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Dump failed!"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Dump successfull!");
|
||||
log_write("dump successfull!!!\n");
|
||||
} else {
|
||||
App::Notify("Dump failed!");
|
||||
log_write("dump failed!!!\n");
|
||||
}
|
||||
|
||||
GcUmountStorage();
|
||||
|
||||
@@ -81,32 +81,28 @@ void from_json(const fs::FsPath& path, GhApiEntry& e) {
|
||||
);
|
||||
}
|
||||
|
||||
auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> bool {
|
||||
auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry* entry) -> Result {
|
||||
static const fs::FsPath temp_file{"/switch/sphaira/cache/github/ghdl.temp"};
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
|
||||
fs::FsNativeSd fs;
|
||||
R_TRY_RESULT(fs.GetFsOpenResult(), false);
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
ON_SCOPE_EXIT(fs.DeleteFile(temp_file));
|
||||
|
||||
if (gh_asset.browser_download_url.empty()) {
|
||||
log_write("failed to find asset\n");
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(!gh_asset.browser_download_url.empty(), 0x1);
|
||||
|
||||
// 2. download the asset
|
||||
if (!pbox->ShouldExit()) {
|
||||
pbox->NewTransfer("Downloading "_i18n + gh_asset.name);
|
||||
log_write("starting download: %s\n", gh_asset.browser_download_url.c_str());
|
||||
|
||||
if (!curl::Api().ToFile(
|
||||
const auto result = curl::Api().ToFile(
|
||||
curl::Url{gh_asset.browser_download_url},
|
||||
curl::Path{temp_file},
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||
).success){
|
||||
log_write("error with download\n");
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
R_UNLESS(result.success, 0x1);
|
||||
}
|
||||
|
||||
fs::FsPath root_path{"/"};
|
||||
@@ -118,28 +114,25 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
||||
if (gh_asset.content_type.find("zip") != gh_asset.content_type.npos) {
|
||||
log_write("found zip\n");
|
||||
auto zfile = unzOpen64(temp_file);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", temp_file.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
|
||||
unz_global_info64 pglobal_info;
|
||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
||||
if (i > 0) {
|
||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
||||
log_write("failed to unzGoToNextFile\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
@@ -147,7 +140,7 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
||||
fs::FsPath file_path;
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
file_path = fs::AppendPath(root_path, file_path);
|
||||
@@ -156,44 +149,37 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
||||
if (file_path[strlen(file_path) -1] == '/') {
|
||||
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
} else {
|
||||
if (R_FAILED(rc = fs.CreateDirectoryRecursivelyWithPath(file_path)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) {
|
||||
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileSetSize(&f, info.uncompressed_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
s64 offset{};
|
||||
while (offset < info.uncompressed_size) {
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
||||
if (bytes_read <= 0) {
|
||||
log_write("failed to read zip file: %s\n", file_path.s);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
|
||||
|
||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
||||
offset += bytes_read;
|
||||
@@ -203,16 +189,14 @@ auto DownloadApp(ProgressBox* pbox, const GhApiAsset& gh_asset, const AssetEntry
|
||||
} else {
|
||||
fs.CreateDirectoryRecursivelyWithPath(root_path);
|
||||
fs.DeleteFile(root_path);
|
||||
if (R_FAILED(fs.RenameFile(temp_file, root_path))) {
|
||||
log_write("failed to rename file: %s -> %s\n", temp_file.s, root_path.s);
|
||||
}
|
||||
R_TRY(fs.RenameFile(temp_file, root_path));
|
||||
}
|
||||
|
||||
log_write("success\n");
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& out) -> bool {
|
||||
auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& out) -> Result {
|
||||
// 1. download the json
|
||||
if (!pbox->ShouldExit()) {
|
||||
pbox->NewTransfer("Downloading json"_i18n);
|
||||
@@ -230,15 +214,12 @@ auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& ou
|
||||
}
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
log_write("json empty\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
R_UNLESS(result.success, 0x1);
|
||||
from_json(result.path, out);
|
||||
}
|
||||
|
||||
return !out.assets.empty();
|
||||
R_UNLESS(!out.assets.empty(), 0x1);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -256,10 +237,12 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
|
||||
static GhApiEntry gh_entry;
|
||||
gh_entry = {};
|
||||
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this](auto pbox) -> Result {
|
||||
return DownloadAssetJson(pbox, GenerateApiUrl(GetEntry()), gh_entry);
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to download json"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
const auto& assets = GetEntry().assets;
|
||||
PopupList::Items asset_items;
|
||||
std::vector<const AssetEntry*> asset_ptr;
|
||||
@@ -304,10 +287,12 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
|
||||
}
|
||||
|
||||
const auto func = [this, &asset_entry, ptr](){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this, &asset_entry, ptr](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, GetEntry().repo, [this, &asset_entry, ptr](auto pbox) -> Result {
|
||||
return DownloadApp(pbox, asset_entry, ptr);
|
||||
}, [this, ptr](bool success){
|
||||
if (success) {
|
||||
}, [this, ptr](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to download app!"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Downloaded "_i18n + GetEntry().repo);
|
||||
auto post_install_message = GetEntry().post_install_message;
|
||||
if (ptr && !ptr->post_install_message.empty()) {
|
||||
@@ -318,7 +303,7 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
|
||||
App::Push(std::make_shared<OptionBox>(post_install_message, "OK"_i18n));
|
||||
}
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
};
|
||||
|
||||
if (!pre_install_message.empty()) {
|
||||
@@ -335,7 +320,7 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} {
|
||||
}
|
||||
}));
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
}}),
|
||||
|
||||
std::make_pair(Button::B, Action{"Back"_i18n, [this](){
|
||||
|
||||
@@ -47,26 +47,25 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
|
||||
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||
};
|
||||
|
||||
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> bool {
|
||||
auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string version) -> Result {
|
||||
static fs::FsPath zip_out{"/switch/sphaira/cache/update.zip"};
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
|
||||
fs::FsNativeSd fs;
|
||||
R_TRY_RESULT(fs.GetFsOpenResult(), false);
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
|
||||
// 1. download the zip
|
||||
if (!pbox->ShouldExit()) {
|
||||
pbox->NewTransfer("Downloading "_i18n + version);
|
||||
log_write("starting download: %s\n", url.c_str());
|
||||
|
||||
if (!curl::Api().ToFile(
|
||||
const auto result = curl::Api().ToFile(
|
||||
curl::Url{url},
|
||||
curl::Path{zip_out},
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||
).success) {
|
||||
log_write("error with download\n");
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
R_UNLESS(result.success, 0x1);
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
|
||||
@@ -74,28 +73,25 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
||||
// 2. extract the zip
|
||||
if (!pbox->ShouldExit()) {
|
||||
auto zfile = unzOpen64(zip_out);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", zip_out.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
|
||||
unz_global_info64 pglobal_info;
|
||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
||||
if (i > 0) {
|
||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
||||
log_write("failed to unzGoToNextFile\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
@@ -103,7 +99,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
||||
fs::FsPath file_path;
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, file_path, sizeof(file_path), 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (file_path[0] != '/') {
|
||||
@@ -118,26 +114,20 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
||||
if (file_path[strlen(file_path) -1] == '/') {
|
||||
if (R_FAILED(rc = fs.CreateDirectoryRecursively(file_path)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create folder: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
} else {
|
||||
Result rc;
|
||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) {
|
||||
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileSetSize(&f, info.uncompressed_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
s64 offset{};
|
||||
@@ -145,13 +135,10 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
||||
if (bytes_read <= 0) {
|
||||
// log_write("failed to read zip file: %s\n", inzip.c_str());
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
|
||||
|
||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
||||
offset += bytes_read;
|
||||
@@ -161,7 +148,7 @@ auto InstallUpdate(ProgressBox* pbox, const std::string url, const std::string v
|
||||
}
|
||||
|
||||
log_write("finished update :)\n");
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
auto CreateRightSideMenu() -> std::shared_ptr<MenuBase> {
|
||||
@@ -293,10 +280,12 @@ MainMenu::MainMenu() {
|
||||
|
||||
if (m_update_state == UpdateState::Update) {
|
||||
options->Add(std::make_shared<SidebarEntryCallback>("Download update: "_i18n + m_update_version, [this](){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, "Sphaira v" + m_update_version, [this](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(0, "Downloading "_i18n, "Sphaira v" + m_update_version, [this](auto pbox) -> Result {
|
||||
return InstallUpdate(pbox, m_update_url, m_update_version);
|
||||
}, [this](bool success){
|
||||
if (success) {
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to download update"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
m_update_state = UpdateState::None;
|
||||
App::Notify("Updated to "_i18n + m_update_version);
|
||||
App::Push(std::make_shared<OptionBox>(
|
||||
@@ -304,10 +293,8 @@ MainMenu::MainMenu() {
|
||||
App::ExitRestart();
|
||||
}
|
||||
));
|
||||
} else {
|
||||
App::Push(std::make_shared<ui::ErrorBox>(MAKERESULT(351, 1), "Failed to download update"_i18n));
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -220,12 +220,12 @@ void from_json(const fs::FsPath& path, PackList& e) {
|
||||
);
|
||||
}
|
||||
|
||||
auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> Result {
|
||||
static const fs::FsPath zip_out{"/switch/sphaira/cache/themezer/temp.zip"};
|
||||
constexpr auto chunk_size = 1024 * 512; // 512KiB
|
||||
|
||||
fs::FsNativeSd fs;
|
||||
R_TRY_RESULT(fs.GetFsOpenResult(), false);
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
|
||||
DownloadPack download_pack;
|
||||
|
||||
@@ -243,7 +243,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
|
||||
if (!result.success || result.data.empty()) {
|
||||
log_write("error with download: %s\n", url.c_str());
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
from_json(result.data, download_pack);
|
||||
@@ -254,13 +254,13 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
pbox->NewTransfer("Downloading "_i18n + entry.details.name);
|
||||
log_write("starting download: %s\n", download_pack.url.c_str());
|
||||
|
||||
if (!curl::Api().ToFile(
|
||||
const auto result = curl::Api().ToFile(
|
||||
curl::Url{download_pack.url},
|
||||
curl::Path{zip_out},
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}).success) {
|
||||
log_write("error with download\n");
|
||||
return false;
|
||||
}
|
||||
curl::OnProgress{pbox->OnDownloadProgressCallback()}
|
||||
);
|
||||
|
||||
R_UNLESS(result.success, 0x1);
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT(fs.DeleteFile(zip_out));
|
||||
@@ -273,28 +273,25 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
// 3. extract the zip
|
||||
if (!pbox->ShouldExit()) {
|
||||
auto zfile = unzOpen64(zip_out);
|
||||
if (!zfile) {
|
||||
log_write("failed to open zip: %s\n", zip_out.s);
|
||||
return false;
|
||||
}
|
||||
R_UNLESS(zfile, 0x1);
|
||||
ON_SCOPE_EXIT(unzClose(zfile));
|
||||
|
||||
unz_global_info64 pglobal_info;
|
||||
if (UNZ_OK != unzGetGlobalInfo64(zfile, &pglobal_info)) {
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pglobal_info.number_entry; i++) {
|
||||
if (i > 0) {
|
||||
if (UNZ_OK != unzGoToNextFile(zfile)) {
|
||||
log_write("failed to unzGoToNextFile\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNZ_OK != unzOpenCurrentFile(zfile)) {
|
||||
log_write("failed to open current file\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
ON_SCOPE_EXIT(unzCloseCurrentFile(zfile));
|
||||
|
||||
@@ -302,7 +299,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
char name[512];
|
||||
if (UNZ_OK != unzGetCurrentFileInfo64(zfile, &info, name, sizeof(name), 0, 0, 0, 0)) {
|
||||
log_write("failed to get current info\n");
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
const auto file_path = fs::AppendPath(dir_path, name);
|
||||
@@ -311,38 +308,27 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
Result rc;
|
||||
if (R_FAILED(rc = fs.CreateFile(file_path, info.uncompressed_size, 0)) && rc != FsError_PathAlreadyExists) {
|
||||
log_write("failed to create file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED(rc = fs.OpenFile(file_path, FsOpenMode_Write, &f))) {
|
||||
log_write("failed to open file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fs.OpenFile(file_path, FsOpenMode_Write, &f));
|
||||
ON_SCOPE_EXIT(fsFileClose(&f));
|
||||
|
||||
if (R_FAILED(rc = fsFileSetSize(&f, info.uncompressed_size))) {
|
||||
log_write("failed to set file size: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileSetSize(&f, info.uncompressed_size));
|
||||
|
||||
std::vector<char> buf(chunk_size);
|
||||
s64 offset{};
|
||||
while (offset < info.uncompressed_size) {
|
||||
if (pbox->ShouldExit()) {
|
||||
return false;
|
||||
}
|
||||
R_TRY(pbox->ShouldExitResult());
|
||||
|
||||
const auto bytes_read = unzReadCurrentFile(zfile, buf.data(), buf.size());
|
||||
if (bytes_read <= 0) {
|
||||
// log_write("failed to read zip file: %s\n", inzip.c_str());
|
||||
return false;
|
||||
R_THROW(0x1);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None))) {
|
||||
log_write("failed to write file: %s 0x%04X\n", file_path.s, rc);
|
||||
return false;
|
||||
}
|
||||
R_TRY(fsFileWrite(&f, offset, buf.data(), bytes_read, FsWriteOption_None));
|
||||
|
||||
pbox->UpdateTransfer(offset, info.uncompressed_size);
|
||||
offset += bytes_read;
|
||||
@@ -351,7 +337,7 @@ auto InstallTheme(ProgressBox* pbox, const PackListEntry& entry) -> bool {
|
||||
}
|
||||
|
||||
log_write("finished install :)\n");
|
||||
return true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -386,13 +372,15 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} {
|
||||
const auto& entry = page.m_packList[m_index];
|
||||
const auto url = apiBuildUrlDownloadPack(entry);
|
||||
|
||||
App::Push(std::make_shared<ProgressBox>(entry.themes[0].preview.lazy_image.image, "Downloading "_i18n, entry.details.name, [this, &entry](auto pbox){
|
||||
App::Push(std::make_shared<ProgressBox>(entry.themes[0].preview.lazy_image.image, "Downloading "_i18n, entry.details.name, [this, &entry](auto pbox) -> Result {
|
||||
return InstallTheme(pbox, entry);
|
||||
}, [this, &entry](bool success){
|
||||
if (success) {
|
||||
}, [this, &entry](Result rc){
|
||||
App::PushErrorBox(rc, "Failed to download theme"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Downloaded "_i18n + entry.details.name);
|
||||
}
|
||||
}, 2));
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,31 +109,31 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
||||
log_write("set to progress\n");
|
||||
m_state = State::Progress;
|
||||
log_write("got connection\n");
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) mutable -> bool {
|
||||
App::Push(std::make_shared<ui::ProgressBox>(0, "Installing "_i18n, "", [this](auto pbox) -> Result {
|
||||
ON_SCOPE_EXIT(m_usb_source->Finished(FINISHED_TIMEOUT));
|
||||
|
||||
log_write("inside progress box\n");
|
||||
for (const auto& file_name : m_names) {
|
||||
m_usb_source->SetFileNameForTranfser(file_name);
|
||||
|
||||
const auto rc = yati::InstallFromSource(pbox, m_usb_source, file_name);
|
||||
if (R_FAILED(rc)) {
|
||||
m_usb_source->SignalCancel();
|
||||
log_write("exiting usb install\n");
|
||||
return false;
|
||||
R_THROW(rc);
|
||||
}
|
||||
|
||||
App::Notify("Installed via usb"_i18n);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [this](bool result){
|
||||
if (result) {
|
||||
R_SUCCEED();
|
||||
}, [this](Result rc){
|
||||
App::PushErrorBox(rc, "USB install failed"_i18n);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
App::Notify("Usb install success!"_i18n);
|
||||
m_state = State::Done;
|
||||
SetPop();
|
||||
} else {
|
||||
App::Notify("Usb install failed!"_i18n);
|
||||
m_state = State::Failed;
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -212,6 +212,13 @@ auto ProgressBox::ShouldExit() -> bool {
|
||||
return m_stop_source.stop_requested();
|
||||
}
|
||||
|
||||
auto ProgressBox::ShouldExitResult() -> Result {
|
||||
if (ShouldExit()) {
|
||||
R_THROW(0xFFFF);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
auto ProgressBox::CopyFile(const fs::FsPath& src_path, const fs::FsPath& dst_path) -> Result {
|
||||
fs::FsNativeSd fs;
|
||||
R_TRY(fs.GetFsOpenResult());
|
||||
|
||||
Reference in New Issue
Block a user