summaryrefslogtreecommitdiffstats
path: root/logic
diff options
context:
space:
mode:
Diffstat (limited to 'logic')
-rw-r--r--logic/CMakeLists.txt4
-rw-r--r--logic/MMCZip.cpp332
-rw-r--r--logic/MMCZip.h57
-rw-r--r--logic/minecraft/JarUtils.cpp158
-rw-r--r--logic/minecraft/JarUtils.h18
-rw-r--r--logic/minecraft/LegacyUpdate.cpp5
-rw-r--r--logic/minecraft/OneSixInstance.cpp1
-rw-r--r--logic/minecraft/OneSixUpdate.cpp4
8 files changed, 396 insertions, 183 deletions
diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt
index 183991af..e3b52ec5 100644
--- a/logic/CMakeLists.txt
+++ b/logic/CMakeLists.txt
@@ -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
diff --git a/logic/MMCZip.cpp b/logic/MMCZip.cpp
new file mode 100644
index 00000000..e2c6d1f5
--- /dev/null
+++ b/logic/MMCZip.cpp
@@ -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;
+}
+
diff --git a/logic/MMCZip.h b/logic/MMCZip.h
new file mode 100644
index 00000000..e1f2ba3a
--- /dev/null
+++ b/logic/MMCZip.h
@@ -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());
+} \ No newline at end of file
diff --git a/logic/minecraft/JarUtils.cpp b/logic/minecraft/JarUtils.cpp
deleted file mode 100644
index b8fb6f0d..00000000
--- a/logic/minecraft/JarUtils.cpp
+++ /dev/null
@@ -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;
-}
-
-}
diff --git a/logic/minecraft/JarUtils.h b/logic/minecraft/JarUtils.h
deleted file mode 100644
index 2e8bd2a7..00000000
--- a/logic/minecraft/JarUtils.h
+++ /dev/null
@@ -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);
-}
diff --git a/logic/minecraft/LegacyUpdate.cpp b/logic/minecraft/LegacyUpdate.cpp
index e2fffbb3..6c0a4cdf 100644
--- a/logic/minecraft/LegacyUpdate.cpp
+++ b/logic/minecraft/LegacyUpdate.cpp
@@ -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;
diff --git a/logic/minecraft/OneSixInstance.cpp b/logic/minecraft/OneSixInstance.cpp
index 7a29c4b4..e9989f2e 100644
--- a/logic/minecraft/OneSixInstance.cpp
+++ b/logic/minecraft/OneSixInstance.cpp
@@ -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"
diff --git a/logic/minecraft/OneSixUpdate.cpp b/logic/minecraft/OneSixUpdate.cpp
index 6cea2341..8a7a1f66 100644
--- a/logic/minecraft/OneSixUpdate.cpp
+++ b/logic/minecraft/OneSixUpdate.cpp
@@ -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;