static int merge_zip(struct zip *za, const char *tname, const char *sname, struct zip **zsp) { struct zip *zs; struct zip_source *source; int i, idx, err; char errstr[1024]; const char *fname; if ((zs=zip_open(sname, 0, &err)) == NULL) { zip_error_to_str(errstr, sizeof(errstr), err, errno); fprintf(stderr, "%s: cannot open zip archive `%s': %s\n", prg, sname, errstr); return -1; } for (i=0; i<zip_get_num_files(zs); i++) { fname = zip_get_name(zs, i, 0); if ((idx=zip_name_locate(za, fname, name_flags)) != -1) { switch (confirm_replace(za, tname, idx, zs, sname, i)) { case 0: break; case 1: if ((source=zip_source_zip(za, zs, i, 0, 0, 0)) == NULL || zip_replace(za, idx, source) < 0) { zip_source_free(source); fprintf(stderr, "%s: cannot replace `%s' in `%s': %s\n", prg, fname, tname, zip_strerror(za)); return -1; } break; case -1: zip_close(zs); return -1; default: fprintf(stderr, "%s: internal error: " "unexpected return code from confirm (%d)\n", prg, err); zip_close(zs); return -1; } } else { if ((source=zip_source_zip(za, zs, i, 0, 0, 0)) == NULL || zip_add(za, fname, source) < 0) { zip_source_free(source); fprintf(stderr, "%s: cannot add `%s' to `%s': %s\n", prg, fname, tname, zip_strerror(za)); zip_close(zs); return -1; } } } *zsp = zs; return 0; }
void GameList::CompressISO(bool decompress) { auto files = GetSelectedGames(); const auto game = GetSelectedGame(); if (files.empty() || !game) return; bool wii_warning_given = false; for (QMutableListIterator<std::shared_ptr<const UICommon::GameFile>> it(files); it.hasNext();) { auto file = it.next(); if ((file->GetPlatform() != DiscIO::Platform::GameCubeDisc && file->GetPlatform() != DiscIO::Platform::WiiDisc) || (decompress && file->GetBlobType() != DiscIO::BlobType::GCZ) || (!decompress && file->GetBlobType() != DiscIO::BlobType::PLAIN)) { it.remove(); continue; } if (!wii_warning_given && !decompress && file->GetPlatform() == DiscIO::Platform::WiiDisc) { ModalMessageBox wii_warning(this); wii_warning.setIcon(QMessageBox::Warning); wii_warning.setWindowTitle(tr("Confirm")); wii_warning.setText(tr("Are you sure?")); wii_warning.setInformativeText(tr( "Compressing a Wii disc image will irreversibly change the compressed copy by removing " "padding data. Your disc image will still work. Continue?")); wii_warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No); if (wii_warning.exec() == QMessageBox::No) return; wii_warning_given = true; } } QString dst_dir; QString dst_path; if (files.size() > 1) { dst_dir = QFileDialog::getExistingDirectory( this, decompress ? tr("Select where you want to save the decompressed images") : tr("Select where you want to save the compressed images"), QFileInfo(QString::fromStdString(game->GetFilePath())).dir().absolutePath()); if (dst_dir.isEmpty()) return; } else { dst_path = QFileDialog::getSaveFileName( this, decompress ? tr("Select where you want to save the decompressed image") : tr("Select where you want to save the compressed image"), QFileInfo(QString::fromStdString(game->GetFilePath())) .dir() .absoluteFilePath( QFileInfo(QString::fromStdString(files[0]->GetFilePath())).completeBaseName()) .append(decompress ? QStringLiteral(".gcm") : QStringLiteral(".gcz")), decompress ? tr("Uncompressed GC/Wii images (*.iso *.gcm)") : tr("Compressed GC/Wii images (*.gcz)")); if (dst_path.isEmpty()) return; } for (const auto& file : files) { const auto original_path = file->GetFilePath(); if (files.size() > 1) { dst_path = QDir(dst_dir) .absoluteFilePath(QFileInfo(QString::fromStdString(original_path)).completeBaseName()) .append(decompress ? QStringLiteral(".gcm") : QStringLiteral(".gcz")); QFileInfo dst_info = QFileInfo(dst_path); if (dst_info.exists()) { ModalMessageBox confirm_replace(this); confirm_replace.setIcon(QMessageBox::Warning); confirm_replace.setWindowTitle(tr("Confirm")); confirm_replace.setText(tr("The file %1 already exists.\n" "Do you wish to replace it?") .arg(dst_info.fileName())); confirm_replace.setStandardButtons(QMessageBox::Yes | QMessageBox::No); if (confirm_replace.exec() == QMessageBox::No) continue; } } QProgressDialog progress_dialog(decompress ? tr("Decompressing...") : tr("Compressing..."), tr("Abort"), 0, 100, this); progress_dialog.setWindowModality(Qt::WindowModal); progress_dialog.setWindowFlags(progress_dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); progress_dialog.setWindowTitle(tr("Progress")); bool good; if (decompress) { if (files.size() > 1) progress_dialog.setLabelText(tr("Decompressing...") + QStringLiteral("\n") + QFileInfo(QString::fromStdString(original_path)).fileName()); good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(), &CompressCB, &progress_dialog); } else { if (files.size() > 1) progress_dialog.setLabelText(tr("Compressing...") + QStringLiteral("\n") + QFileInfo(QString::fromStdString(original_path)).fileName()); good = DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(), file->GetPlatform() == DiscIO::Platform::WiiDisc ? 1 : 0, 16384, &CompressCB, &progress_dialog); } if (!good) { QErrorMessage(this).showMessage(tr("Dolphin failed to complete the requested action.")); return; } } ModalMessageBox::information(this, tr("Success"), decompress ? tr("Successfully decompressed %n image(s).", "", files.size()) : tr("Successfully compressed %n image(s).", "", files.size())); }