diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 126 |
1 files changed, 100 insertions, 26 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f2e6c03f0..21df742cb 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1447,6 +1447,8 @@ void GMainWindow::ConnectWidgetEvents() { &GMainWindow::OnGameListRemoveInstalledEntry); connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile); connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS); + connect(game_list, &GameList::VerifyIntegrityRequested, this, + &GMainWindow::OnGameListVerifyIntegrity); connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, &GMainWindow::OnGameListNavigateToGamedbEntry); @@ -2275,40 +2277,62 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } -static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { - std::size_t out = 0; - - for (const auto& subdir : dir->GetSubdirectories()) { - out += 1 + CalculateRomFSEntrySize(subdir, full); - } - - return out + (full ? dir->GetFiles().size() : 0); -} - -static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src, - const FileSys::VirtualDir& dest, std::size_t block_size, bool full) { +static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, + const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest, + bool full) { if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) return false; if (dialog.wasCanceled()) return false; + std::vector<u8> buffer(CopyBufferSize); + auto last_timestamp = std::chrono::steady_clock::now(); + + const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file, + const FileSys::VirtualFile& dest_file) { + if (src_file == nullptr || dest_file == nullptr) { + return false; + } + if (!dest_file->Resize(src_file->GetSize())) { + return false; + } + + for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) { + if (dialog.wasCanceled()) { + dest_file->Resize(0); + return false; + } + + using namespace std::literals::chrono_literals; + const auto new_timestamp = std::chrono::steady_clock::now(); + + if ((new_timestamp - last_timestamp) > 33ms) { + last_timestamp = new_timestamp; + dialog.setValue( + static_cast<int>(std::min(read_size, total_size) * 100 / total_size)); + QCoreApplication::processEvents(); + } + + const auto read = src_file->Read(buffer.data(), buffer.size(), i); + dest_file->Write(buffer.data(), read, i); + + read_size += read; + } + + return true; + }; + if (full) { for (const auto& file : src->GetFiles()) { const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); - if (!FileSys::VfsRawCopy(file, out, block_size)) - return false; - dialog.setValue(dialog.value() + 1); - if (dialog.wasCanceled()) + if (!QtRawCopy(file, out)) return false; } } for (const auto& dir : src->GetSubdirectories()) { const auto out = dest->CreateSubdirectory(dir->GetName()); - if (!RomFSRawCopy(dialog, dir, out, block_size, full)) - return false; - dialog.setValue(dialog.value() + 1); - if (dialog.wasCanceled()) + if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full)) return false; } @@ -2653,10 +2677,9 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } const auto full = res == selections.constFirst(); - const auto entry_size = CalculateRomFSEntrySize(extracted, full); - // The minimum required space is the size of the extracted RomFS + 1 GiB - const auto minimum_free_space = extracted->GetSize() + 0x40000000; + // The expected required space is the size of the RomFS + 1 GiB + const auto minimum_free_space = romfs->GetSize() + 0x40000000; if (full && Common::FS::GetFreeSpaceSize(path) < minimum_free_space) { QMessageBox::warning(this, tr("RomFS Extraction Failed!"), @@ -2667,12 +2690,15 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } - QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, - static_cast<s32>(entry_size), this); + QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); - if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) { + size_t read_size = 0; + + if (RomFSRawCopy(romfs->GetSize(), read_size, progress, extracted, out, full)) { progress.close(); QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), tr("The operation completed successfully.")); @@ -2684,6 +2710,54 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } } +void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { + const auto NotImplemented = [this] { + QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"), + tr("File contents were not checked for validity.")); + }; + const auto Failed = [this] { + QMessageBox::critical(this, tr("Integrity verification failed!"), + tr("File contents may be corrupt.")); + }; + + const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); + if (loader == nullptr) { + NotImplemented(); + return; + } + + QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + const auto QtProgressCallback = [&](size_t processed_size, size_t total_size) { + if (progress.wasCanceled()) { + return false; + } + + progress.setValue(static_cast<int>((processed_size * 100) / total_size)); + return true; + }; + + const auto status = loader->VerifyIntegrity(QtProgressCallback); + if (progress.wasCanceled() || + status == Loader::ResultStatus::ErrorIntegrityVerificationNotImplemented) { + NotImplemented(); + return; + } + + if (status == Loader::ResultStatus::ErrorIntegrityVerificationFailed) { + Failed(); + return; + } + + progress.close(); + QMessageBox::information(this, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); +} + void GMainWindow::OnGameListCopyTID(u64 program_id) { QClipboard* clipboard = QGuiApplication::clipboard(); clipboard->setText(QString::fromStdString(fmt::format("{:016X}", program_id))); |