NOISSUE refactor and rearrange zip file utils
This commit is contained in:
		| @@ -323,7 +323,7 @@ namespace Ui { | ||||
| #include <QShortcut> | ||||
| #include <QFileDialog> | ||||
|  | ||||
| #include <JlCompress.h> | ||||
| #include <MMCZip.h> | ||||
|  | ||||
| #include "osutils.h" | ||||
| #include "userutils.h" | ||||
| @@ -1095,7 +1095,7 @@ void MainWindow::instanceFromZipPack(QString instName, QString instGroup, QStrin | ||||
| 	QTemporaryDir extractTmpDir; | ||||
| 	QDir extractDir(extractTmpDir.path()); | ||||
| 	qDebug() << "Attempting to create instance from" << archivePath; | ||||
| 	if (JlCompress::extractDir(archivePath, extractDir.absolutePath()).isEmpty()) | ||||
| 	if (MMCZip::extractDir(archivePath, extractDir.absolutePath()).isEmpty()) | ||||
| 	{ | ||||
| 		CustomMessageBox::selectable(this, tr("Error"), | ||||
| 										tr("Failed to extract modpack"), QMessageBox::Warning)->show(); | ||||
| @@ -1471,92 +1471,6 @@ void MainWindow::on_actionDeleteInstance_triggered() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #include <pathutils.h> | ||||
|  | ||||
| bool compressSubDir(QuaZip* zip, QString dir, QString origDir, QString prefix) | ||||
| { | ||||
| 	if (!zip) return false; | ||||
| 	if (zip->getMode()!=QuaZip::mdCreate && zip->getMode()!=QuaZip::mdAppend && zip->getMode()!=QuaZip::mdAdd) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QDir directory(dir); | ||||
| 	if (!directory.exists()) return false; | ||||
|  | ||||
| 	QDir origDirectory(origDir); | ||||
| 	if (dir != origDir) | ||||
| 	{ | ||||
| 		QuaZipFile dirZipFile(zip); | ||||
| 		auto dirPrefix = PathCombine(prefix, origDirectory.relativeFilePath(dir)) + "/"; | ||||
| 		if (!dirZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(dirPrefix, dir), 0, 0, 0)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 		dirZipFile.close(); | ||||
| 	} | ||||
|  | ||||
| 	QFileInfoList files = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); | ||||
| 	for (auto file: files) | ||||
| 	{ | ||||
| 		if(!compressSubDir(zip,file.absoluteFilePath(),origDir, prefix)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	files = directory.entryInfoList(QDir::Files); | ||||
| 	for (auto file: files) | ||||
| 	{ | ||||
| 		if(!file.isFile()) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if(file.absoluteFilePath()==zip->getZipName()) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); | ||||
| 		if(prefix.size()) | ||||
| 		{ | ||||
| 			filename = PathCombine(prefix, filename); | ||||
| 		} | ||||
| 		if (!JlCompress::compressFile(zip,file.absoluteFilePath(),filename)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool compressDir(QString zipFile, QString dir, QString prefix = QString()) | ||||
| { | ||||
| 	QuaZip zip(zipFile); | ||||
| 	QDir().mkpath(QFileInfo(zipFile).absolutePath()); | ||||
| 	if(!zip.open(QuaZip::mdCreate)) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QSet<QString> added; | ||||
| 	if (!compressSubDir(&zip,dir,dir,prefix)) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
| 	zip.close(); | ||||
| 	if(zip.getZipError()!=0) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void MainWindow::on_actionExportInstance_triggered() | ||||
| { | ||||
| 	if (m_selectedInstance) | ||||
| @@ -1580,7 +1494,7 @@ void MainWindow::on_actionExportInstance_triggered() | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (!compressDir(output, m_selectedInstance->instanceRoot(), name)) | ||||
| 		if (!MMCZip::compressDir(output, m_selectedInstance->instanceRoot(), name)) | ||||
| 		{ | ||||
| 			QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); | ||||
| 		} | ||||
|   | ||||
| @@ -15,6 +15,8 @@ SET(LOGIC_SOURCES | ||||
| 	BaseInstance.cpp | ||||
| 	NullInstance.h | ||||
| 	MMCError.h | ||||
| 	MMCZip.h | ||||
| 	MMCZip.cpp | ||||
|  | ||||
| 	# WARNING: globals live here | ||||
| 	Env.h | ||||
| @@ -101,8 +103,6 @@ SET(LOGIC_SOURCES | ||||
| 	minecraft/LwjglVersionList.cpp | ||||
| 	minecraft/SkinUtils.h | ||||
| 	minecraft/SkinUtils.cpp | ||||
| 	minecraft/JarUtils.h | ||||
| 	minecraft/JarUtils.cpp | ||||
| 	minecraft/GradleSpecifier.h | ||||
| 	minecraft/MinecraftProfile.cpp | ||||
| 	minecraft/MinecraftProfile.h | ||||
|   | ||||
							
								
								
									
										332
									
								
								logic/MMCZip.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								logic/MMCZip.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
| /* | ||||
| Copyright (C) 2010 Roberto Pompermaier | ||||
| Copyright (C) 2005-2014 Sergey A. Tachenov | ||||
|  | ||||
| Parts of this file were part of QuaZIP. | ||||
|  | ||||
| QuaZIP is free software: you can redistribute it and/or modify | ||||
| it under the terms of the GNU Lesser General Public License as published by | ||||
| the Free Software Foundation, either version 2.1 of the License, or | ||||
| (at your option) any later version. | ||||
|  | ||||
| QuaZIP is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| GNU Lesser General Public License for more details. | ||||
|  | ||||
| You should have received a copy of the GNU Lesser General Public License | ||||
| along with QuaZIP.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| See COPYING file for the full LGPL text. | ||||
|  | ||||
| Original ZIP package is copyrighted by Gilles Vollant and contributors, | ||||
| see quazip/(un)MMCZip.h files for details. Basically it's the zlib license. | ||||
| */ | ||||
|  | ||||
| #include <pathutils.h> | ||||
| #include <quazip.h> | ||||
| #include <JlCompress.h> | ||||
| #include "MMCZip.h" | ||||
|  | ||||
| #include <QDebug> | ||||
|  | ||||
| bool copyData(QIODevice &inFile, QIODevice &outFile) | ||||
| { | ||||
| 	while (!inFile.atEnd()) | ||||
| 	{ | ||||
| 		char buf[4096]; | ||||
| 		qint64 readLen = inFile.read(buf, 4096); | ||||
| 		if (readLen <= 0) | ||||
| 			return false; | ||||
| 		if (outFile.write(buf, readLen) != readLen) | ||||
| 			return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| QStringList MMCZip::extractDir(QString fileCompressed, QString dir) | ||||
| { | ||||
| 	return JlCompress::extractDir(fileCompressed, dir); | ||||
| } | ||||
|  | ||||
| bool compressFile(QuaZip *zip, QString fileName, QString fileDest) | ||||
| { | ||||
| 	if (!zip) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend && | ||||
| 		zip->getMode() != QuaZip::mdAdd) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QFile inFile; | ||||
| 	inFile.setFileName(fileName); | ||||
| 	if (!inFile.open(QIODevice::ReadOnly)) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QuaZipFile outFile(zip); | ||||
| 	if (!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	if (!copyData(inFile, outFile) || outFile.getZipError() != UNZ_OK) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	outFile.close(); | ||||
| 	if (outFile.getZipError() != UNZ_OK) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	inFile.close(); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MMCZip::compressSubDir(QuaZip* zip, QString dir, QString origDir, QSet<QString>& added,  QString prefix) | ||||
| { | ||||
| 	if (!zip) return false; | ||||
| 	if (zip->getMode()!=QuaZip::mdCreate && zip->getMode()!=QuaZip::mdAppend && zip->getMode()!=QuaZip::mdAdd) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QDir directory(dir); | ||||
| 	if (!directory.exists()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QDir origDirectory(origDir); | ||||
| 	if (dir != origDir) | ||||
| 	{ | ||||
| 		QuaZipFile dirZipFile(zip); | ||||
| 		auto dirPrefix = PathCombine(prefix, origDirectory.relativeFilePath(dir)) + "/"; | ||||
| 		if (!dirZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(dirPrefix, dir), 0, 0, 0)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 		dirZipFile.close(); | ||||
| 	} | ||||
|  | ||||
| 	QFileInfoList files = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); | ||||
| 	for (auto file: files) | ||||
| 	{ | ||||
| 		if(!file.isDir()) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 		if(!compressSubDir(zip,file.absoluteFilePath(),origDir, added, prefix)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	files = directory.entryInfoList(QDir::Files); | ||||
| 	for (auto file: files) | ||||
| 	{ | ||||
| 		if(!file.isFile()) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if(file.absoluteFilePath()==zip->getZipName()) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); | ||||
| 		if(prefix.size()) | ||||
| 		{ | ||||
| 			filename = PathCombine(prefix, filename); | ||||
| 		} | ||||
| 		added.insert(filename); | ||||
| 		if (!compressFile(zip,file.absoluteFilePath(),filename)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, | ||||
| 				   std::function<bool(QString)> filter) | ||||
| { | ||||
| 	QuaZip modZip(from.filePath()); | ||||
| 	modZip.open(QuaZip::mdUnzip); | ||||
|  | ||||
| 	QuaZipFile fileInsideMod(&modZip); | ||||
| 	QuaZipFile zipOutFile(into); | ||||
| 	for (bool more = modZip.goToFirstFile(); more; more = modZip.goToNextFile()) | ||||
| 	{ | ||||
| 		QString filename = modZip.getCurrentFileName(); | ||||
| 		if (!filter(filename)) | ||||
| 		{ | ||||
| 			qDebug() << "Skipping file " << filename << " from " | ||||
| 						<< from.fileName() << " - filtered"; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (contained.contains(filename)) | ||||
| 		{ | ||||
| 			qDebug() << "Skipping already contained file " << filename << " from " | ||||
| 						<< from.fileName(); | ||||
| 			continue; | ||||
| 		} | ||||
| 		contained.insert(filename); | ||||
|  | ||||
| 		if (!fileInsideMod.open(QIODevice::ReadOnly)) | ||||
| 		{ | ||||
| 			qCritical() << "Failed to open " << filename << " from " << from.fileName(); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		QuaZipNewInfo info_out(fileInsideMod.getActualFileName()); | ||||
|  | ||||
| 		if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) | ||||
| 		{ | ||||
| 			qCritical() << "Failed to open " << filename << " in the jar"; | ||||
| 			fileInsideMod.close(); | ||||
| 			return false; | ||||
| 		} | ||||
| 		if (!copyData(fileInsideMod, zipOutFile)) | ||||
| 		{ | ||||
| 			zipOutFile.close(); | ||||
| 			fileInsideMod.close(); | ||||
| 			qCritical() << "Failed to copy data of " << filename << " into the jar"; | ||||
| 			return false; | ||||
| 		} | ||||
| 		zipOutFile.close(); | ||||
| 		fileInsideMod.close(); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& 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<QString> addedFiles; | ||||
|  | ||||
| 	// Modify the jar | ||||
| 	QListIterator<Mod> 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, noFilter)) | ||||
| 			{ | ||||
| 				zipOut.close(); | ||||
| 				QFile::remove(targetJarPath); | ||||
| 				qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		else if (mod.type() == Mod::MOD_SINGLEFILE) | ||||
| 		{ | ||||
| 			auto filename = mod.filename(); | ||||
| 			if (!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) | ||||
| 		{ | ||||
| 			auto filename = mod.filename(); | ||||
| 			QString what_to_zip = filename.absoluteFilePath(); | ||||
| 			QDir dir(what_to_zip); | ||||
| 			dir.cdUp(); | ||||
| 			QString parent_dir = dir.absolutePath(); | ||||
| 			if (!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(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, metaInfFilter)) | ||||
| 	{ | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| bool MMCZip::noFilter(QString) | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MMCZip::metaInfFilter(QString key) | ||||
| { | ||||
| 	if(key.contains("META-INF")) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool MMCZip::compressDir(QString zipFile, QString dir, QString prefix) | ||||
| { | ||||
| 	QuaZip zip(zipFile); | ||||
| 	QDir().mkpath(QFileInfo(zipFile).absolutePath()); | ||||
| 	if(!zip.open(QuaZip::mdCreate)) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	QSet<QString> added; | ||||
| 	if (!compressSubDir(&zip, dir, dir, added, prefix)) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
| 	zip.close(); | ||||
| 	if(zip.getZipError()!=0) | ||||
| 	{ | ||||
| 		QFile::remove(zipFile); | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
							
								
								
									
										57
									
								
								logic/MMCZip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								logic/MMCZip.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QString> | ||||
| #include <QFileInfo> | ||||
| #include <QSet> | ||||
| #include "minecraft/Mod.h" | ||||
| #include <functional> | ||||
|  | ||||
| class QuaZip; | ||||
|  | ||||
| namespace MMCZip | ||||
| { | ||||
|     /** | ||||
| 	 * Compress a subdirectory. | ||||
| 	 * \param parentZip Opened zip containing the parent directory. | ||||
| 	 * \param dir The full path to the directory to pack. | ||||
| 	 * \param parentDir The full path to the directory corresponding to the root of the ZIP. | ||||
| 	 * \param recursive Whether to pack sub-directories as well or only files. | ||||
| 	 * \return true if success, false otherwise. | ||||
|      */ | ||||
| 	bool compressSubDir(QuaZip* zip, QString dir, QString origDir, QSet<QString>& added, QString prefix = QString()); | ||||
|  | ||||
| 	/** | ||||
| 	 * Compress a whole directory. | ||||
| 	 * \param fileCompressed The name of the archive. | ||||
| 	 * \param dir The directory to compress. | ||||
| 	 * \param recursive Whether to pack the subdirectories as well, or just regular files. | ||||
| 	 * \return true if success, false otherwise. | ||||
| 	 */ | ||||
| 	bool compressDir(QString zipFile, QString dir, QString prefix = QString()); | ||||
|  | ||||
| 	/// filter function for @mergeZipFiles - passthrough | ||||
| 	bool noFilter(QString key); | ||||
|  | ||||
| 	/// filter function for @mergeZipFiles - ignores METAINF | ||||
| 	bool metaInfFilter(QString key); | ||||
|  | ||||
| 	/** | ||||
| 	 * Merge two zip files, using a filter function | ||||
| 	 */ | ||||
| 	bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, std::function<bool(QString)> filter); | ||||
|  | ||||
| 	/** | ||||
| 	 * take a source jar, add mods to it, resulting in target jar | ||||
| 	 */ | ||||
| 	bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods); | ||||
|  | ||||
| 	/** | ||||
| 	 * Extract a whole archive. | ||||
| 	 * | ||||
| 	 * \param fileCompressed The name of the archive. | ||||
| 	 * \param dir The directory to extract to, the current directory if | ||||
| 	 * left empty. | ||||
| 	 * \return The list of the full paths of the files extracted, empty on failure. | ||||
| 	 */ | ||||
|     QStringList extractDir(QString fileCompressed, QString dir = QString()); | ||||
| } | ||||
| @@ -1,158 +0,0 @@ | ||||
| #include "minecraft/JarUtils.h" | ||||
| #include <quazip.h> | ||||
| #include <quazipfile.h> | ||||
| #include <JlCompress.h> | ||||
| #include <QDebug> | ||||
|  | ||||
| namespace JarUtils { | ||||
|  | ||||
| bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, | ||||
| 				   std::function<bool(QString)> filter) | ||||
| { | ||||
| 	QuaZip modZip(from.filePath()); | ||||
| 	modZip.open(QuaZip::mdUnzip); | ||||
|  | ||||
| 	QuaZipFile fileInsideMod(&modZip); | ||||
| 	QuaZipFile zipOutFile(into); | ||||
| 	for (bool more = modZip.goToFirstFile(); more; more = modZip.goToNextFile()) | ||||
| 	{ | ||||
| 		QString filename = modZip.getCurrentFileName(); | ||||
| 		if (!filter(filename)) | ||||
| 		{ | ||||
| 			qDebug() << "Skipping file " << filename << " from " | ||||
| 						<< from.fileName() << " - filtered"; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (contained.contains(filename)) | ||||
| 		{ | ||||
| 			qDebug() << "Skipping already contained file " << filename << " from " | ||||
| 						<< from.fileName(); | ||||
| 			continue; | ||||
| 		} | ||||
| 		contained.insert(filename); | ||||
|  | ||||
| 		if (!fileInsideMod.open(QIODevice::ReadOnly)) | ||||
| 		{ | ||||
| 			qCritical() << "Failed to open " << filename << " from " << from.fileName(); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		QuaZipNewInfo info_out(fileInsideMod.getActualFileName()); | ||||
|  | ||||
| 		if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) | ||||
| 		{ | ||||
| 			qCritical() << "Failed to open " << filename << " in the jar"; | ||||
| 			fileInsideMod.close(); | ||||
| 			return false; | ||||
| 		} | ||||
| 		if (!JlCompress::copyData(fileInsideMod, zipOutFile)) | ||||
| 		{ | ||||
| 			zipOutFile.close(); | ||||
| 			fileInsideMod.close(); | ||||
| 			qCritical() << "Failed to copy data of " << filename << " into the jar"; | ||||
| 			return false; | ||||
| 		} | ||||
| 		zipOutFile.close(); | ||||
| 		fileInsideMod.close(); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& 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<QString> addedFiles; | ||||
|  | ||||
| 	// Modify the jar | ||||
| 	QListIterator<Mod> 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, noFilter)) | ||||
| 			{ | ||||
| 				zipOut.close(); | ||||
| 				QFile::remove(targetJarPath); | ||||
| 				qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		else if (mod.type() == Mod::MOD_SINGLEFILE) | ||||
| 		{ | ||||
| 			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) | ||||
| 		{ | ||||
| 			auto filename = mod.filename(); | ||||
| 			QString what_to_zip = filename.absoluteFilePath(); | ||||
| 			QDir dir(what_to_zip); | ||||
| 			dir.cdUp(); | ||||
| 			QString parent_dir = dir.absolutePath(); | ||||
| 			if (!JlCompress::compressSubDir(&zipOut, what_to_zip, parent_dir, true, 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(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, metaInfFilter)) | ||||
| 	{ | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| bool noFilter(QString) | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool metaInfFilter(QString key) | ||||
| { | ||||
| 	if(key.contains("META-INF")) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| #pragma once | ||||
| #include <QString> | ||||
| #include <QFileInfo> | ||||
| #include <QSet> | ||||
| #include "Mod.h" | ||||
| #include <functional> | ||||
|  | ||||
| class QuaZip; | ||||
| namespace JarUtils | ||||
| { | ||||
| 	bool noFilter(QString); | ||||
| 	bool metaInfFilter(QString key); | ||||
|  | ||||
| 	bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, | ||||
| 				   std::function<bool(QString)> filter); | ||||
|  | ||||
| 	bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods); | ||||
| } | ||||
| @@ -17,14 +17,13 @@ | ||||
| #include <pathutils.h> | ||||
| #include <quazip.h> | ||||
| #include <quazipfile.h> | ||||
| #include <JlCompress.h> | ||||
| #include <QDebug> | ||||
|  | ||||
| #include "Env.h" | ||||
| #include "BaseInstance.h" | ||||
| #include "net/URLConstants.h" | ||||
| #include "MMCZip.h" | ||||
|  | ||||
| #include "minecraft/JarUtils.h" | ||||
| #include "minecraft/LegacyUpdate.h" | ||||
| #include "minecraft/LwjglVersionList.h" | ||||
| #include "minecraft/MinecraftVersionList.h" | ||||
| @@ -455,7 +454,7 @@ void LegacyUpdate::ModTheJar() | ||||
| 	QString outputJarPath = runnableJar.filePath(); | ||||
| 	QString inputJarPath = baseJar.filePath(); | ||||
|  | ||||
| 	if(!JarUtils::createModdedJar(inputJarPath, outputJarPath, modList)) | ||||
| 	if(!MMCZip::createModdedJar(inputJarPath, outputJarPath, modList)) | ||||
| 	{ | ||||
| 		emitFailed(tr("Failed to create the custom Minecraft jar file.")); | ||||
| 		return; | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| #include "minecraft/VersionBuildError.h" | ||||
| #include "minecraft/MinecraftProcess.h" | ||||
| #include "minecraft/OneSixProfileStrategy.h" | ||||
| #include "MMCZip.h" | ||||
|  | ||||
| #include "minecraft/AssetsUtils.h" | ||||
| #include "icons/IconList.h" | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
| #include "forge/ForgeMirrors.h" | ||||
| #include "net/URLConstants.h" | ||||
| #include "minecraft/AssetsUtils.h" | ||||
| #include "minecraft/JarUtils.h" | ||||
| #include "MMCZip.h" | ||||
|  | ||||
| OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent), m_inst(inst) | ||||
| { | ||||
| @@ -320,7 +320,7 @@ void OneSixUpdate::jarlibFinished() | ||||
| 		auto metacache = ENV.metacache(); | ||||
| 		auto entry = metacache->resolveEntry("versions", localPath); | ||||
| 		QString fullJarPath = entry->getFullPath(); | ||||
| 		if(!JarUtils::createModdedJar(sourceJarPath, finalJarPath, jarMods)) | ||||
| 		if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) | ||||
| 		{ | ||||
| 			emitFailed(tr("Failed to create the custom Minecraft jar file.")); | ||||
| 			return; | ||||
|   | ||||
							
								
								
									
										169
									
								
								quazip.patch
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								quazip.patch
									
									
									
									
									
								
							| @@ -3,9 +3,9 @@ Index: CMakeLists.txt | ||||
| --- CMakeLists.txt	(revision 250) | ||||
| +++ CMakeLists.txt	(working copy) | ||||
| @@ -51,4 +51,4 @@ | ||||
|   | ||||
|  | ||||
|  add_subdirectory(quazip) | ||||
|   | ||||
|  | ||||
| -install(FILES FindQuaZip.cmake DESTINATION ${CMAKE_ROOT}/Modules) | ||||
| +#install(FILES FindQuaZip.cmake DESTINATION ${CMAKE_ROOT}/Modules) | ||||
| Index: quazip/CMakeLists.txt | ||||
| @@ -15,7 +15,7 @@ Index: quazip/CMakeLists.txt | ||||
| @@ -14,10 +14,14 @@ | ||||
|  qt_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS}) | ||||
|  set(SRCS ${SRCS} ${MOC_SRCS}) | ||||
|   | ||||
|  | ||||
| -add_library(quazip SHARED ${SRCS}) | ||||
| -set_target_properties(quazip PROPERTIES VERSION 1.0.0 SOVERSION 1) | ||||
| +add_library(quazip STATIC ${SRCS}) | ||||
| @@ -27,165 +27,6 @@ Index: quazip/CMakeLists.txt | ||||
| +if(WIN32) | ||||
| +    add_definitions(-DZ_PREFIX) | ||||
| +endif() | ||||
|   | ||||
|  | ||||
|  install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip) | ||||
|  install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION}) | ||||
| Index: quazip/JlCompress.cpp | ||||
| =================================================================== | ||||
| --- quazip/JlCompress.cpp	(revision 250) | ||||
| +++ quazip/JlCompress.cpp	(working copy) | ||||
| @@ -26,7 +26,7 @@ | ||||
|  #include "JlCompress.h" | ||||
|  #include <QDebug> | ||||
|   | ||||
| -static bool copyData(QIODevice &inFile, QIODevice &outFile) | ||||
| +bool JlCompress::copyData(QIODevice &inFile, QIODevice &outFile) | ||||
|  { | ||||
|      while (!inFile.atEnd()) { | ||||
|          char buf[4096]; | ||||
| @@ -100,7 +100,7 @@ | ||||
|   * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa | ||||
|   * funzione. | ||||
|   */ | ||||
| -bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { | ||||
| +bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QSet<QString>& added) { | ||||
|      // zip: oggetto dove aggiungere il file | ||||
|      // dir: cartella reale corrente | ||||
|      // origDir: cartella reale originale | ||||
| @@ -133,7 +133,7 @@ | ||||
|          QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot); | ||||
|          Q_FOREACH (QFileInfo file, files) { | ||||
|              // Comprimo la sotto cartella | ||||
| -            if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false; | ||||
| +			if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,added)) return false; | ||||
|          } | ||||
|      } | ||||
|   | ||||
| @@ -148,6 +148,7 @@ | ||||
|   | ||||
|          // Comprimo il file | ||||
|          if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; | ||||
| +		added.insert(filename); | ||||
|      } | ||||
|   | ||||
|      return true; | ||||
| @@ -344,8 +345,9 @@ | ||||
|          return false; | ||||
|      } | ||||
|   | ||||
| +	QSet<QString> added; | ||||
|      // Aggiungo i file e le sotto cartelle | ||||
| -    if (!compressSubDir(&zip,dir,dir,recursive)) { | ||||
| +	if (!compressSubDir(&zip,dir,dir,recursive,added)) { | ||||
|          QFile::remove(fileCompressed); | ||||
|          return false; | ||||
|      } | ||||
| @@ -437,6 +439,53 @@ | ||||
|      return extracted; | ||||
|  } | ||||
|   | ||||
| +QStringList JlCompress::extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions) | ||||
| +{ | ||||
| +	QuaZip zip(fileCompressed); | ||||
| +	if(!zip.open(QuaZip::mdUnzip)) | ||||
| +	{ | ||||
| +		return QStringList(); | ||||
| +	} | ||||
| + | ||||
| +	QDir directory(dir); | ||||
| +	QStringList extracted; | ||||
| +	if (!zip.goToFirstFile()) | ||||
| +	{ | ||||
| +		return QStringList(); | ||||
| +	} | ||||
| +	do | ||||
| +	{ | ||||
| +		QString name = zip.getCurrentFileName(); | ||||
| +		bool ok = true; | ||||
| +		for(auto str: exceptions) | ||||
| +		{ | ||||
| +			if(name.startsWith(str)) | ||||
| +			{ | ||||
| +				ok = false; | ||||
| +				break; | ||||
| +			} | ||||
| +		} | ||||
| +		if(!ok) | ||||
| +			continue; | ||||
| +		QString absFilePath = directory.absoluteFilePath(name); | ||||
| +		if (!JlCompress::extractFile(&zip, "", absFilePath)) | ||||
| +		{ | ||||
| +			JlCompress::removeFile(extracted); | ||||
| +			return QStringList(); | ||||
| +		} | ||||
| +		extracted.append(absFilePath); | ||||
| +	} while (zip.goToNextFile()); | ||||
| + | ||||
| +	zip.close(); | ||||
| +	if(zip.getZipError()!=0) | ||||
| +	{ | ||||
| +		JlCompress::removeFile(extracted); | ||||
| +		return QStringList(); | ||||
| +	} | ||||
| + | ||||
| +	return extracted; | ||||
| +} | ||||
| + | ||||
|  /**OK | ||||
|   * Estrae il file fileCompressed nella cartella dir. | ||||
|   * Se dir = "" allora il file viene estratto nella cartella corrente. | ||||
| Index: quazip/JlCompress.h | ||||
| =================================================================== | ||||
| --- quazip/JlCompress.h	(revision 250) | ||||
| +++ quazip/JlCompress.h	(working copy) | ||||
| @@ -40,7 +40,7 @@ | ||||
|    simple operations, such as mass ZIP packing or extraction. | ||||
|    */ | ||||
|  class QUAZIP_EXPORT JlCompress { | ||||
| -private: | ||||
| +public: | ||||
|      /// Compress a single file. | ||||
|      /** | ||||
|        \param zip Opened zip to compress the file to. | ||||
| @@ -59,7 +59,7 @@ | ||||
|        files. | ||||
|        \return true if success, false otherwise. | ||||
|        */ | ||||
| -    static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); | ||||
| +	static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive, QSet<QString>& added); | ||||
|      /// Extract a single file. | ||||
|      /** | ||||
|        \param zip The opened zip archive to extract from. | ||||
| @@ -68,6 +68,7 @@ | ||||
|        \return true if success, false otherwise. | ||||
|        */ | ||||
|      static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); | ||||
| +private: | ||||
|      /// Remove some files. | ||||
|      /** | ||||
|        \param listFile The list of files to remove. | ||||
| @@ -76,6 +77,8 @@ | ||||
|      static bool removeFile(QStringList listFile); | ||||
|   | ||||
|  public: | ||||
| +	/// copy data from inFile to outFile | ||||
| +	static bool copyData(QIODevice &inFile, QIODevice &outFile); | ||||
|      /// Compress a single file. | ||||
|      /** | ||||
|        \param fileCompressed The name of the archive. | ||||
| @@ -127,6 +130,15 @@ | ||||
|        \return The list of the full paths of the files extracted, empty on failure. | ||||
|        */ | ||||
|      static QStringList extractDir(QString fileCompressed, QString dir = QString()); | ||||
| +	/// Extract a whole archive, with a list of exceptions (prefixes to ignore). | ||||
| +	/** | ||||
| +	  \param fileCompressed The name of the archive. | ||||
| +	  \param dir The directory to extract to, the current directory if | ||||
| +	  left empty. | ||||
| +	  \param exceptions The list of exception prefixes | ||||
| +	  \return The list of the full paths of the files extracted, empty on failure. | ||||
| +	  */ | ||||
| +	static QStringList extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions); | ||||
|      /// Get the file list. | ||||
|      /** | ||||
|        \return The list of the files in the archive, or, more precisely, the | ||||
|  install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION}) | ||||
		Reference in New Issue
	
	Block a user