From efa414c442a77735a5f972b7103e8ce866a6bdd1 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 20 Jan 2022 20:40:56 +0100 Subject: refactor: initial migration to QuaZip 1.2 Let's move off our custom QuaZip. In the olden times we needed the custom version of QuaZip, as it was basically unmaintained and on SourceForge (eww). But nowadays it's maintained and on GitHub. See new GitHub page: https://github.com/stachenov/quazip --- launcher/ui/dialogs/ExportInstanceDialog.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index 1a164875..59ae0a76 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -378,6 +378,7 @@ void SaveIcon(InstancePtr m_instance) bool ExportInstanceDialog::doExport() { + /* auto name = FS::RemoveInvalidFilenameChars(m_instance->name()); const QString output = QFileDialog::getSaveFileName( @@ -404,11 +405,11 @@ bool ExportInstanceDialog::doExport() auto & blocked = proxyModel->blockedPaths(); using std::placeholders::_1; if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1))) - { + { */ QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); return false; - } - return true; + /*} + return true;*/ } void ExportInstanceDialog::done(int result) -- cgit From 81c72c2038f35e744e038923105d91add5a0732c Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 24 Jan 2022 23:02:06 +0100 Subject: refactor: bring back methods that need to be reimplemented --- launcher/MMCZip.cpp | 95 +++++++++++++++++++++++++++ launcher/minecraft/launch/ModMinecraftJar.cpp | 8 +-- launcher/ui/dialogs/ExportInstanceDialog.cpp | 10 +-- 3 files changed, 104 insertions(+), 9 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 74c9b388..36562b06 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -78,6 +78,101 @@ bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet &containe return true; } +// ours +bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) +{ + QuaZip zipOut(targetJarPath); + if (!zipOut.open(QuaZip::mdCreate)) + { + QFile::remove(targetJarPath); + qCritical() << "Failed to open the minecraft.jar for modding"; + return false; + } + // Files already added to the jar. + // These files will be skipped. + QSet addedFiles; + + // Modify the jar + QListIterator i(mods); + i.toBack(); + while (i.hasPrevious()) + { + const Mod &mod = i.previous(); + // do not merge disabled mods. + if (!mod.enabled()) + continue; + if (mod.type() == Mod::MOD_ZIPFILE) + { + if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles)) + { + zipOut.close(); + QFile::remove(targetJarPath); + qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; + return false; + } + } + else if (mod.type() == Mod::MOD_SINGLEFILE) + { + // FIXME: buggy - does not work with addedFiles + auto filename = mod.filename(); + if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) + { + zipOut.close(); + QFile::remove(targetJarPath); + qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; + return false; + } + addedFiles.insert(filename.fileName()); + } + else if (mod.type() == Mod::MOD_FOLDER) + { + // FIXME: buggy - does not work with addedFiles + auto filename = mod.filename(); + QString what_to_zip = filename.absoluteFilePath(); + QDir dir(what_to_zip); + dir.cdUp(); + QString parent_dir = dir.absolutePath(); + return false; + // TODO: implement custom compressSubDir: + if (!JlCompress::compressSubDir(&zipOut, what_to_zip, parent_dir, addedFiles)) + { + zipOut.close(); + QFile::remove(targetJarPath); + qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; + return false; + } + qDebug() << "Adding folder " << filename.fileName() << " from " + << filename.absoluteFilePath(); + } + else + { + // Make sure we do not continue launching when something is missing or undefined... + zipOut.close(); + QFile::remove(targetJarPath); + qCritical() << "Failed to add unknown mod type" << mod.filename().fileName() << "to the jar."; + return false; + } + } + + if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key){return !key.contains("META-INF");})) + { + zipOut.close(); + QFile::remove(targetJarPath); + qCritical() << "Failed to insert minecraft.jar contents."; + return false; + } + + // Recompress the jar + zipOut.close(); + if (zipOut.getZipError() != 0) + { + QFile::remove(targetJarPath); + qCritical() << "Failed to finalize minecraft.jar!"; + return false; + } + return true; +} + // ours QString MMCZip::findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root) { diff --git a/launcher/minecraft/launch/ModMinecraftJar.cpp b/launcher/minecraft/launch/ModMinecraftJar.cpp index c8796f01..93de9d59 100644 --- a/launcher/minecraft/launch/ModMinecraftJar.cpp +++ b/launcher/minecraft/launch/ModMinecraftJar.cpp @@ -42,7 +42,6 @@ void ModMinecraftJar::executeTask() emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath)); } - /* // create temporary modded jar, if needed auto components = m_inst->getPackProfile(); auto profile = components->getProfile(); @@ -54,13 +53,12 @@ void ModMinecraftJar::executeTask() mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath()); auto sourceJarPath = jars[0]; if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) - { */ - // TODO: add back support for modded jar + { emitFailed(tr("Failed to create the custom Minecraft jar file.")); return; - /*} + } } - emitSucceeded();*/ + emitSucceeded(); } void ModMinecraftJar::finalize() diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index 59ae0a76..fb9c6542 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -378,7 +378,6 @@ void SaveIcon(InstancePtr m_instance) bool ExportInstanceDialog::doExport() { - /* auto name = FS::RemoveInvalidFilenameChars(m_instance->name()); const QString output = QFileDialog::getSaveFileName( @@ -404,12 +403,15 @@ bool ExportInstanceDialog::doExport() auto & blocked = proxyModel->blockedPaths(); using std::placeholders::_1; + QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); + return false; + // TODO Reimplement custom compressDir: if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1))) - { */ + { QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); return false; - /*} - return true;*/ + } + return true; } void ExportInstanceDialog::done(int result) -- cgit From a8089b76c0e7961e31b96cdd203e3c345183645b Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Fri, 28 Jan 2022 12:37:22 +0100 Subject: fix: bring back instance exports --- launcher/MMCZip.cpp | 60 ++++++++++++++++++++++++++++ launcher/MMCZip.h | 18 +++++++++ launcher/ui/dialogs/ExportInstanceDialog.cpp | 11 +++-- 3 files changed, 85 insertions(+), 4 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 9b8b7908..90e586d8 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -311,3 +311,63 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target) } return MMCZip::extractRelFile(&zip, file, target); } + +bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList *files, + MMCZip::FilterFunction excludeFilter) { + QDir rootDirectory(rootDir); + if (!rootDirectory.exists()) return false; + + QDir directory; + if (subDir == nullptr) + directory = rootDirectory; + else + directory = QDir(subDir); + + if (!directory.exists()) return false; // shouldn't ever happen + + // recurse directories + QFileInfoList entries = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); + for (const auto& e: entries) { + if (!collectFileListRecursively(rootDir, e.filePath(), files, excludeFilter)) + return false; + } + + // collect files + entries = directory.entryInfoList(QDir::Files); + for (const auto& e: entries) { + QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath()); + if (excludeFilter && excludeFilter(relativeFilePath)) { + qDebug() << "Skipping file " << relativeFilePath; + continue; + } + + files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles + } + return true; +} + +bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files) +{ + QuaZip zip(fileCompressed); + QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); + if(!zip.open(QuaZip::mdCreate)) { + QFile::remove(fileCompressed); + return false; + } + + QDir directory(dir); + if (!directory.exists()) return false; + + for (auto e : files) { + auto filePath = directory.relativeFilePath(e.absoluteFilePath()); + if( !JlCompress::compressFile(&zip, e.absoluteFilePath(), filePath)) return false; + } + + zip.close(); + if(zip.getZipError()!=0) { + QFile::remove(fileCompressed); + return false; + } + + return true; +} diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index c8e830ab..29ae2a63 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -90,4 +90,22 @@ namespace MMCZip */ bool extractFile(QString fileCompressed, QString file, QString dir); + /** + * Populate a QFileInfoList with a directory tree recursively, while allowing to excludeFilter what shouldn't be included. + * \param rootDir directory to start off + * \param subDir subdirectory, should be nullptr for first invocation + * \param files resulting list of QFileInfo + * \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude) + * \return true for success or false for failure + */ + bool collectFileListRecursively(const QString &rootDir, const QString &subDir, QFileInfoList *files, FilterFunction excludeFilter); + + /** + * Compress directory, by providing a list of files to compress + * \param fileCompressed target archive file + * \param dir directory that will be compressed (to compress with relative paths) + * \param files list of files to compress + * \return true for success or false for failure + */ + bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files); } diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index fb9c6542..f3bf7abe 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -403,10 +403,13 @@ bool ExportInstanceDialog::doExport() auto & blocked = proxyModel->blockedPaths(); using std::placeholders::_1; - QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); - return false; - // TODO Reimplement custom compressDir: - if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1))) + auto files = QFileInfoList(); + if (!MMCZip::collectFileListRecursively(m_instance->instanceRoot(), nullptr, &files, + std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1))) { + QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); + return false; + } + if (!MMCZip::compressDirFiles(output, m_instance->instanceRoot(), files)) { QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); return false; -- cgit