fix hang when importing certain modpacks

Modified findFolderOfFileInZip to use a breadth-first search and support
searching for multiple file names in one pass. This should prevent or at
least make it less likely to hang while importing certain packs.

Signed-off-by: Lenny McLennington <lenny@sneed.church>
This commit is contained in:
Lenny McLennington 2023-10-28 20:28:35 +01:00
parent b995074440
commit e2875ef9a5
4 changed files with 32 additions and 29 deletions

View File

@ -164,23 +164,21 @@ void InstanceImportTask::processZipPack()
} }
else else
{ {
QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg"); auto [rootDirectory, fileName] = MMCZip::findFolderOfFileInZip(m_packZip.get(), {"manifest.json", "instance.cfg"});
QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json"); if(fileName == "manifest.json")
if (!mmcRoot.isNull())
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcRoot;
root = mmcRoot;
m_modpackType = ModpackType::MultiMC;
}
else if(!flameRoot.isNull())
{ {
// process as Flame pack // process as Flame pack
qDebug() << "Flame:" << flameRoot; qDebug() << "Flame:" << rootDirectory;
root = flameRoot; root = rootDirectory;
m_modpackType = ModpackType::Flame; m_modpackType = ModpackType::Flame;
} }
else if (fileName == "instance.cfg")
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << rootDirectory;
root = rootDirectory;
m_modpackType = ModpackType::MultiMC;
}
} }
if(m_modpackType == ModpackType::Unknown) if(m_modpackType == ModpackType::Unknown)
{ {

View File

@ -40,6 +40,7 @@
#include "FileSystem.h" #include "FileSystem.h"
#include <QDebug> #include <QDebug>
#include <deque>
// ours // ours
bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const FilterFunction filter) bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const FilterFunction filter)
@ -228,23 +229,27 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
} }
// ours // ours
QString MMCZip::findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root) std::pair<QString, QString> MMCZip::findFolderOfFileInZip(QuaZip * zip, QSet<const QString> what, const QString &root)
{ {
QuaZipDir rootDir(zip, root); std::deque<QString> pathsToTraverse;
for(auto fileName: rootDir.entryList(QDir::Files)) pathsToTraverse.push_back(root);
while (!pathsToTraverse.empty())
{ {
if(fileName == what) QString currentPath = pathsToTraverse.front();
return root; pathsToTraverse.pop_front();
} QuaZipDir rootDir(zip, currentPath);
for(auto fileName: rootDir.entryList(QDir::Dirs))
{ for(auto fileName: rootDir.entryList(QDir::Files))
QString result = findFolderOfFileInZip(zip, what, root + fileName);
if(!result.isEmpty())
{ {
return result; if (what.contains(fileName))
return {currentPath, fileName};
}
for(auto fileName: rootDir.entryList(QDir::Dirs))
{
pathsToTraverse.push_back(root);
} }
} }
return QString(); return {QString(), QString()};
} }
// ours // ours

View File

@ -78,11 +78,11 @@ namespace MMCZip
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods); bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
/** /**
* Find a single file in archive by file name (not path) * Breath-first find a single file in archive by a list of file names (not path)
* *
* \return the path prefix where the file is * \return pair of {file parent directory, file name}
*/ */
QString findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root = QString("")); std::pair<QString, QString> findFolderOfFileInZip(QuaZip * zip, QSet<const QString> what, const QString &root = QString(""));
/** /**
* Find a multiple files of the same name in archive by file name * Find a multiple files of the same name in archive by file name

View File

@ -285,7 +285,7 @@ void World::readFromZip(const QFileInfo &file)
{ {
return; return;
} }
auto location = MMCZip::findFolderOfFileInZip(&zip, "level.dat"); auto [location, _] = MMCZip::findFolderOfFileInZip(&zip, {"level.dat"});
is_valid = !location.isEmpty(); is_valid = !location.isEmpty();
if (!is_valid) if (!is_valid)
{ {