#include "JarUtils.h" #include #include #include #include namespace JarUtils { bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, std::function 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)) { QLOG_INFO() << "Skipping file " << filename << " from " << from.fileName() << " - filtered"; continue; } if (contained.contains(filename)) { QLOG_INFO() << "Skipping already contained file " << filename << " from " << from.fileName(); continue; } contained.insert(filename); QLOG_INFO() << "Adding file " << filename << " from " << from.fileName(); if (!fileInsideMod.open(QIODevice::ReadOnly)) { QLOG_ERROR() << "Failed to open " << filename << " from " << from.fileName(); return false; } QuaZipNewInfo info_out(fileInsideMod.getActualFileName()); if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) { QLOG_ERROR() << "Failed to open " << filename << " in the jar"; fileInsideMod.close(); return false; } if (!JlCompress::copyData(fileInsideMod, zipOutFile)) { zipOutFile.close(); fileInsideMod.close(); QLOG_ERROR() << "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& mods) { QuaZip zipOut(targetJarPath); if (!zipOut.open(QuaZip::mdCreate)) { QFile::remove(targetJarPath); QLOG_ERROR() << "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, noFilter)) { zipOut.close(); QFile::remove(targetJarPath); QLOG_ERROR() << "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); QLOG_ERROR() << "Failed to add" << mod.filename().fileName() << "to the jar."; return false; } addedFiles.insert(filename.fileName()); QLOG_INFO() << "Adding file " << filename.fileName() << " from " << filename.absoluteFilePath(); } 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); QLOG_ERROR() << "Failed to add" << mod.filename().fileName() << "to the jar."; return false; } QLOG_INFO() << "Adding folder " << filename.fileName() << " from " << filename.absoluteFilePath(); } } if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, metaInfFilter)) { zipOut.close(); QFile::remove(targetJarPath); QLOG_ERROR() << "Failed to insert minecraft.jar contents."; return false; } // Recompress the jar zipOut.close(); if (zipOut.getZipError() != 0) { QFile::remove(targetJarPath); QLOG_ERROR() << "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; } }