diff --git a/src/core/inner_fat.cpp b/src/core/inner_fat.cpp index 7f656dd..992ae27 100644 --- a/src/core/inner_fat.cpp +++ b/src/core/inner_fat.cpp @@ -22,6 +22,10 @@ bool InnerFAT::IsGood() const { } bool InnerFAT::ExtractDirectory(const std::string& path, std::size_t index) const { + if (index >= directory_entry_table.size()) { + LOG_ERROR(Core, "Index out of bound {}", index); + return false; + } auto entry = directory_entry_table[index]; std::array name_data = {}; // Append a null terminator @@ -152,6 +156,10 @@ bool SDSavegame::ExtractFile(const std::string& path, std::size_t index) const { return false; } + if (index >= file_entry_table.size()) { + LOG_ERROR(Core, "Index out of bound {}", index); + return false; + } auto entry = file_entry_table[index]; std::array name_data = {}; // Append a null terminator @@ -305,6 +313,10 @@ bool SDExtdata::ExtractFile(const std::string& path, std::size_t index) const { /// Maximum amount of device files a device directory can hold. constexpr u32 DeviceDirCapacity = 126; + if (index >= file_entry_table.size()) { + LOG_ERROR(Core, "Index out of bound {}", index); + return false; + } auto entry = file_entry_table[index]; std::array name_data = {}; // Append a null terminator diff --git a/src/frontend/helpers/import_job.cpp b/src/frontend/helpers/import_job.cpp index ade1371..2486d7a 100644 --- a/src/frontend/helpers/import_job.cpp +++ b/src/frontend/helpers/import_job.cpp @@ -21,8 +21,7 @@ void ImportJob::run() { if (!importer.ImportContent(content, callback)) { importer.DeleteContent(content); if (!cancelled) { - emit ErrorOccured(content); - return; + failed_contents.emplace_back(content); } } count++; @@ -39,3 +38,7 @@ void ImportJob::Cancel() { cancelled.store(true); importer.AbortImporting(); } + +std::vector ImportJob::GetFailedContents() const { + return failed_contents; +} diff --git a/src/frontend/helpers/import_job.h b/src/frontend/helpers/import_job.h index 17b7423..b016d7b 100644 --- a/src/frontend/helpers/import_job.h +++ b/src/frontend/helpers/import_job.h @@ -19,6 +19,8 @@ public: void run() override; void Cancel(); + std::vector GetFailedContents() const; + signals: /** * Called when progress is updated on the current content. @@ -32,12 +34,12 @@ signals: void NextContent(u64 size_imported, u64 count, Core::ContentSpecifier next_content); void Completed(); - void ErrorOccured(Core::ContentSpecifier current_content); private: std::atomic_bool cancelled{false}; Core::SDMCImporter& importer; std::vector contents; + std::vector failed_contents; }; Q_DECLARE_METATYPE(Core::ContentSpecifier) diff --git a/src/frontend/import_dialog.cpp b/src/frontend/import_dialog.cpp index 009ee7c..66a0faf 100644 --- a/src/frontend/import_dialog.cpp +++ b/src/frontend/import_dialog.cpp @@ -495,16 +495,25 @@ void ImportDialog::StartImporting() { .arg(ReadableByteSize(current_size_imported)) .arg(ReadableByteSize(current_content.maximum_size))); }); - connect(job, &ImportJob::ErrorOccured, this, - [this, dialog](Core::ContentSpecifier current_content) { - QMessageBox::critical(this, tr("Error"), - tr("Failed to import content %1 (%2)!") - .arg(GetContentName(current_content)) - .arg(GetContentTypeName(current_content.type))); - dialog->hide(); - }); - connect(job, &ImportJob::Completed, this, [this, dialog] { + connect(job, &ImportJob::Completed, this, [this, dialog, job] { dialog->setValue(dialog->maximum()); + + const auto failed_contents = job->GetFailedContents(); + if (failed_contents.empty()) { + QMessageBox::information(this, tr("Import Completed"), + tr("Successfully imported the selected contents.")); + } else { + QString list_content; + for (const auto& content : failed_contents) { + list_content.append(QStringLiteral("
  • %1 (%2)
  • ") + .arg(GetContentName(content)) + .arg(GetContentTypeName(content.type))); + } + QMessageBox::critical( + this, tr("Import Failed"), + tr("The following contents couldn't be imported:
      %1
    ").arg(list_content)); + } + RelistContent(); }); connect(dialog, &QProgressDialog::canceled, this, [this, dialog, job] {