1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-18 17:40:48 +02:00
vcmi/launcher/modManager/chroniclesextractor.cpp

167 lines
4.3 KiB
C++
Raw Normal View History

2024-08-30 21:17:18 +02:00
/*
* chroniclesextractor.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "chroniclesextractor.h"
2024-08-30 22:20:33 +02:00
#include "../../lib/VCMIDirs.h"
#ifdef ENABLE_INNOEXTRACT
#include "cli/extract.hpp"
#include "setup/version.hpp"
#endif
ChroniclesExtractor::ChroniclesExtractor(QWidget *p, std::function<void(float percent)> cb) :
parent(p), cb(cb)
2024-08-30 21:17:18 +02:00
{
2024-08-30 22:20:33 +02:00
}
bool ChroniclesExtractor::handleTempDir(bool create)
{
if(create)
2024-08-30 21:17:18 +02:00
{
2024-08-30 22:20:33 +02:00
tempDir = QDir(pathToQString(VCMIDirs::get().userDataPath()));
if(tempDir.cd("tmp"))
2024-08-30 21:17:18 +02:00
{
2024-08-30 22:20:33 +02:00
tempDir.removeRecursively(); // remove if already exists (e.g. previous run)
tempDir.cdUp();
2024-08-30 21:17:18 +02:00
}
2024-08-30 22:20:33 +02:00
tempDir.mkdir("tmp");
if(!tempDir.cd("tmp"))
return false; // should not happen - but avoid deleting wrong folder in any case
}
else
tempDir.removeRecursively();
return true;
}
int ChroniclesExtractor::getChronicleNo(QFile & file)
{
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::critical(parent, tr("File cannot opened"), file.errorString());
return 0;
}
2024-08-30 21:17:18 +02:00
2024-08-30 22:20:33 +02:00
QByteArray magic{"MZ"};
QByteArray magicFile = file.read(magic.length());
if(!magicFile.startsWith(magic))
{
QMessageBox::critical(parent, tr("Invalid file selected"), tr("You have to select an gog installer file!"));
return 0;
}
QByteArray dataBegin = file.read(1'000'000);
const std::map<int, QByteArray> chronicles = {
{1, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Warlords of the Wasteland"), 90}},
{2, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Conquest of the Underworld"), 92}},
{3, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Masters of the Elements"), 86}},
{4, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Clash of the Dragons"), 80}},
{5, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The World Tree"), 68}},
{6, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Fiery Moon"), 68}},
{7, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Revolt of the Beastmasters"), 92}},
{8, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Sword of Frost"), 76}}
};
int chronicle = 0;
for (const auto& kv : chronicles) {
if(dataBegin.contains(kv.second))
2024-08-30 21:17:18 +02:00
{
2024-08-30 22:20:33 +02:00
chronicle = kv.first;
break;
2024-08-30 21:17:18 +02:00
}
2024-08-30 22:20:33 +02:00
}
if(!chronicle)
{
QMessageBox::critical(parent, tr("Invalid file selected"), tr("You have to select an chronicle installer file!"));
return 0;
}
return chronicle;
}
2024-08-30 21:17:18 +02:00
2024-08-30 22:20:33 +02:00
bool ChroniclesExtractor::extractGogInstaller(QString file)
{
#ifndef ENABLE_INNOEXTRACT
QMessageBox::critical(parent, tr("Innoextract functionality missing"), "VCMI was compiled without innoextract support, which is needed to extract chroncles!");
return false;
#else
::extract_options o;
o.extract = true;
// standard settings
o.gog_galaxy = true;
o.codepage = 0U;
o.output_dir = tempDir.path().toStdString();
o.extract_temp = true;
o.extract_unknown = true;
o.filenames.set_expand(true);
o.preserve_file_times = true; // also correctly closes file -> without it: on Windows the files are not written completely
QString errorText = "";
try
{
process_file(file.toStdString(), o, [this](float progress) {
float overallProgress = ((1.0 / float(fileCount)) * float(extractionFile)) + (progress / float(fileCount));
if(cb)
cb(overallProgress);
});
2024-08-30 21:17:18 +02:00
}
2024-08-30 22:20:33 +02:00
catch(const std::ios_base::failure & e)
{
errorText = tr("Stream error while extracting files!\nerror reason: ");
errorText += e.what();
}
catch(const format_error & e)
{
errorText = e.what();
}
catch(const std::runtime_error & e)
{
errorText = e.what();
}
catch(const setup::version_error &)
{
errorText = tr("Not a supported Inno Setup installer!");
}
if(!errorText.isEmpty())
{
QMessageBox::critical(parent, tr("Extracting error!"), errorText);
return false;
}
return true;
#endif
}
void ChroniclesExtractor::installChronicles(QStringList exe)
{
extractionFile = -1;
fileCount = exe.size();
for(QString f : exe)
{
extractionFile++;
QFile file(f);
int chronicleNo = getChronicleNo(file);
if(!chronicleNo)
continue;
if(!handleTempDir(true))
continue;
if(!extractGogInstaller(f))
continue;
if(!handleTempDir(false))
continue;
2024-08-30 21:17:18 +02:00
}
}