mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 01:56:44 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			924 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			924 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "unshieldworker.hpp"
 | 
						|
 | 
						|
#include <QDebug>
 | 
						|
 | 
						|
#include <QReadLocker>
 | 
						|
#include <QWriteLocker>
 | 
						|
#include <QFileDialog>
 | 
						|
#include <QFileInfo>
 | 
						|
#include <QFileInfoListIterator>
 | 
						|
#include <QStringList>
 | 
						|
#include <QTextStream>
 | 
						|
#include <QTextCodec>
 | 
						|
#include <QFile>
 | 
						|
#include <QDir>
 | 
						|
#include <QDirIterator>
 | 
						|
 | 
						|
Wizard::UnshieldWorker::UnshieldWorker(QObject *parent) :
 | 
						|
    QObject(parent),
 | 
						|
    mIniSettings()
 | 
						|
{
 | 
						|
    unshield_set_log_level(0);
 | 
						|
 | 
						|
    mPath = QString();
 | 
						|
    mIniPath = QString();
 | 
						|
    mDiskPath = QString();
 | 
						|
 | 
						|
    // Default to Latin encoding
 | 
						|
    mIniCodec = QTextCodec::codecForName("windows-1252");
 | 
						|
 | 
						|
    mInstallMorrowind = false;
 | 
						|
    mInstallTribunal = false;
 | 
						|
    mInstallBloodmoon = false;
 | 
						|
 | 
						|
    mMorrowindDone = false;
 | 
						|
    mTribunalDone = false;
 | 
						|
    mBloodmoonDone = false;
 | 
						|
 | 
						|
    mStopped = false;
 | 
						|
 | 
						|
    qRegisterMetaType<Wizard::Component>("Wizard::Component");
 | 
						|
}
 | 
						|
 | 
						|
Wizard::UnshieldWorker::~UnshieldWorker()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::stopWorker()
 | 
						|
{
 | 
						|
    mMutex.lock();
 | 
						|
    mStopped = true;
 | 
						|
    mMutex.unlock();
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setInstallComponent(Wizard::Component component, bool install)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    switch (component) {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        mInstallMorrowind = install;
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        mInstallTribunal = install;
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        mInstallBloodmoon = install;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::getInstallComponent(Component component)
 | 
						|
{
 | 
						|
    QReadLocker readLock(&mLock);
 | 
						|
    switch (component) {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        return mInstallMorrowind;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        return mInstallTribunal;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        return mInstallBloodmoon;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setComponentDone(Component component, bool done)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    switch (component) {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        mMorrowindDone = done;
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        mTribunalDone = done;
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        mBloodmoonDone = done;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::getComponentDone(Component component)
 | 
						|
{
 | 
						|
    QReadLocker readLock(&mLock);
 | 
						|
    switch (component)
 | 
						|
    {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        return mMorrowindDone;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        return mTribunalDone;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        return mBloodmoonDone;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setPath(const QString &path)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    mPath = path;
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setIniPath(const QString &path)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    mIniPath = path;
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setDiskPath(const QString &path)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    mDiskPath = path;
 | 
						|
    mWait.wakeAll();
 | 
						|
}
 | 
						|
 | 
						|
QString Wizard::UnshieldWorker::getPath()
 | 
						|
{
 | 
						|
    QReadLocker readLock(&mLock);
 | 
						|
    return mPath;
 | 
						|
}
 | 
						|
 | 
						|
QString Wizard::UnshieldWorker::getIniPath()
 | 
						|
{
 | 
						|
    QReadLocker readLock(&mLock);
 | 
						|
    return mIniPath;
 | 
						|
}
 | 
						|
 | 
						|
QString Wizard::UnshieldWorker::getDiskPath()
 | 
						|
{
 | 
						|
    QReadLocker readLock(&mLock);
 | 
						|
    return mDiskPath;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::setIniCodec(QTextCodec *codec)
 | 
						|
{
 | 
						|
    QWriteLocker writeLock(&mLock);
 | 
						|
    mIniCodec = codec;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::setupSettings()
 | 
						|
{
 | 
						|
    // Create Morrowind.ini settings map
 | 
						|
    if (getIniPath().isEmpty())
 | 
						|
        return false;
 | 
						|
 | 
						|
    QFile file(getIniPath());
 | 
						|
 | 
						|
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | 
						|
        emit error(tr("Failed to open Morrowind configuration file!"),
 | 
						|
                   tr("Opening %1 failed: %2.").arg(getIniPath(), file.errorString()));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    QTextStream stream(&file);
 | 
						|
    stream.setCodec(mIniCodec);
 | 
						|
 | 
						|
    mIniSettings.readFile(stream);
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::writeSettings()
 | 
						|
{
 | 
						|
    if (getIniPath().isEmpty())
 | 
						|
        return false;
 | 
						|
 | 
						|
    QFile file(getIniPath());
 | 
						|
 | 
						|
    if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
 | 
						|
        emit error(tr("Failed to open Morrowind configuration file!"),
 | 
						|
                   tr("Opening %1 failed: %2.").arg(getIniPath(), file.errorString()));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    QTextStream stream(&file);
 | 
						|
    stream.setCodec(mIniCodec);
 | 
						|
 | 
						|
    if (!mIniSettings.writeFile(getIniPath(), stream)) {
 | 
						|
         emit error(tr("Failed to write Morrowind configuration file!"),
 | 
						|
                    tr("Writing to %1 failed: %2.").arg(getIniPath(), file.errorString()));
 | 
						|
         return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::removeDirectory(const QString &dirName)
 | 
						|
{
 | 
						|
    bool result = false;
 | 
						|
    QDir dir(dirName);
 | 
						|
 | 
						|
    if (dir.exists(dirName))
 | 
						|
    {
 | 
						|
        QFileInfoList list(dir.entryInfoList(QDir::NoDotAndDotDot |
 | 
						|
                                               QDir::System | QDir::Hidden |
 | 
						|
                                               QDir::AllDirs | QDir::Files, QDir::DirsFirst));
 | 
						|
        foreach(QFileInfo info, list) {
 | 
						|
            if (info.isDir()) {
 | 
						|
                result = removeDirectory(info.absoluteFilePath());
 | 
						|
            } else {
 | 
						|
                result = QFile::remove(info.absoluteFilePath());
 | 
						|
            }
 | 
						|
 | 
						|
            if (!result)
 | 
						|
                return result;
 | 
						|
        }
 | 
						|
 | 
						|
        result = dir.rmdir(dirName);
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::copyFile(const QString &source, const QString &destination, bool keepSource)
 | 
						|
{
 | 
						|
    QDir dir;
 | 
						|
    QFile file;
 | 
						|
 | 
						|
    QFileInfo info(destination);
 | 
						|
 | 
						|
    if (info.exists()) {
 | 
						|
        if (!dir.remove(info.absoluteFilePath()))
 | 
						|
            return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (file.copy(source, destination)) {
 | 
						|
        if (!keepSource) {
 | 
						|
            if (!file.remove(source))
 | 
						|
                return false;
 | 
						|
        } else {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::copyDirectory(const QString &source, const QString &destination, bool keepSource)
 | 
						|
{
 | 
						|
    QDir sourceDir(source);
 | 
						|
    QDir destDir(destination);
 | 
						|
    bool result = true;
 | 
						|
 | 
						|
    if (!destDir.exists()) {
 | 
						|
        if (!sourceDir.mkpath(destination))
 | 
						|
            return false;
 | 
						|
    }
 | 
						|
 | 
						|
    destDir.refresh();
 | 
						|
 | 
						|
    if (!destDir.exists())
 | 
						|
        return false;
 | 
						|
 | 
						|
    QFileInfoList list(sourceDir.entryInfoList(QDir::NoDotAndDotDot |
 | 
						|
                                                 QDir::System | QDir::Hidden |
 | 
						|
                                                 QDir::AllDirs | QDir::Files, QDir::DirsFirst));
 | 
						|
 | 
						|
    foreach (const QFileInfo &info, list) {
 | 
						|
        QString relativePath(info.absoluteFilePath());
 | 
						|
        relativePath.remove(source);
 | 
						|
 | 
						|
        QString destinationPath(destDir.absolutePath() + relativePath);
 | 
						|
 | 
						|
        if (info.isSymLink())
 | 
						|
            continue;
 | 
						|
 | 
						|
        if (info.isDir()) {
 | 
						|
            result = copyDirectory(info.absoluteFilePath(), destinationPath);
 | 
						|
        } else {
 | 
						|
            result = copyFile(info.absoluteFilePath(), destinationPath);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!keepSource)
 | 
						|
        return result && removeDirectory(sourceDir.absolutePath());
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::installFile(const QString &fileName, const QString &path, Qt::MatchFlags flags, bool keepSource)
 | 
						|
{
 | 
						|
    return installFiles(fileName, path, flags, true, keepSource);
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::installFiles(const QString &fileName, const QString &path, Qt::MatchFlags flags, bool keepSource, bool single)
 | 
						|
{
 | 
						|
    QDir dir(path);
 | 
						|
 | 
						|
    if (!dir.exists())
 | 
						|
        return false;
 | 
						|
 | 
						|
    QStringList files(findFiles(fileName, path, flags));
 | 
						|
 | 
						|
    foreach (const QString &file, files) {
 | 
						|
        QFileInfo info(file);
 | 
						|
        emit textChanged(tr("Installing: %1").arg(info.fileName()));
 | 
						|
 | 
						|
        if (single) {
 | 
						|
            return copyFile(info.absoluteFilePath(), getPath() + QDir::separator() + info.fileName(), keepSource);
 | 
						|
        } else {
 | 
						|
            if (!copyFile(info.absoluteFilePath(), getPath() + QDir::separator() + info.fileName(), keepSource))
 | 
						|
                return false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::installDirectories(const QString &dirName, const QString &path, bool recursive, bool keepSource)
 | 
						|
{
 | 
						|
    QDir dir(path);
 | 
						|
 | 
						|
    if (!dir.exists())
 | 
						|
        return false;
 | 
						|
 | 
						|
    QStringList directories(findDirectories(dirName, path, recursive));
 | 
						|
 | 
						|
    foreach (const QString &dir, directories) {
 | 
						|
        QFileInfo info(dir);
 | 
						|
        emit textChanged(tr("Installing: %1 directory").arg(info.fileName()));
 | 
						|
        if (!copyDirectory(info.absoluteFilePath(), getPath() + QDir::separator() + info.fileName(), keepSource))
 | 
						|
            return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
void Wizard::UnshieldWorker::extract()
 | 
						|
{
 | 
						|
    if (getInstallComponent(Wizard::Component_Morrowind))
 | 
						|
    {
 | 
						|
        if (!getComponentDone(Wizard::Component_Morrowind))
 | 
						|
            if (!setupComponent(Wizard::Component_Morrowind))
 | 
						|
                return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Tribunal))
 | 
						|
    {
 | 
						|
        if (!getComponentDone(Wizard::Component_Tribunal))
 | 
						|
            if (!setupComponent(Wizard::Component_Tribunal))
 | 
						|
                return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Bloodmoon))
 | 
						|
    {
 | 
						|
        if (!getComponentDone(Wizard::Component_Bloodmoon))
 | 
						|
            if (!setupComponent(Wizard::Component_Bloodmoon))
 | 
						|
                return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Update Morrowind configuration
 | 
						|
    if (getInstallComponent(Wizard::Component_Tribunal))
 | 
						|
    {
 | 
						|
        mIniSettings.setValue(QLatin1String("Archives/Archive 0"), QVariant(QString("Tribunal.bsa")));
 | 
						|
        mIniSettings.setValue(QLatin1String("Game Files/GameFile1"), QVariant(QString("Tribunal.esm")));
 | 
						|
    }
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Bloodmoon))
 | 
						|
    {
 | 
						|
        mIniSettings.setValue(QLatin1String("Archives/Archive 0"), QVariant(QString("Bloodmoon.bsa")));
 | 
						|
        mIniSettings.setValue(QLatin1String("Game Files/GameFile1"), QVariant(QString("Bloodmoon.esm")));
 | 
						|
    }
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Tribunal) &&
 | 
						|
            getInstallComponent(Wizard::Component_Bloodmoon))
 | 
						|
    {
 | 
						|
        mIniSettings.setValue(QLatin1String("Archives/Archive 0"), QVariant(QString("Tribunal.bsa")));
 | 
						|
        mIniSettings.setValue(QLatin1String("Archives/Archive 1"), QVariant(QString("Bloodmoon.bsa")));
 | 
						|
        mIniSettings.setValue(QLatin1String("Game Files/GameFile1"), QVariant(QString("Tribunal.esm")));
 | 
						|
        mIniSettings.setValue(QLatin1String("Game Files/GameFile2"), QVariant(QString("Bloodmoon.esm")));
 | 
						|
    }
 | 
						|
 | 
						|
    // Write the settings to the Morrowind config file
 | 
						|
    if (!writeSettings())
 | 
						|
        return;
 | 
						|
 | 
						|
    // Remove the temporary directory
 | 
						|
    removeDirectory(getPath() + QDir::separator() + QLatin1String("extract-temp"));
 | 
						|
 | 
						|
    // Fill the progress bar
 | 
						|
    int total = 0;
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Morrowind))
 | 
						|
        total = 100;
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Tribunal))
 | 
						|
        total = total + 100;
 | 
						|
 | 
						|
    if (getInstallComponent(Wizard::Component_Bloodmoon))
 | 
						|
        total = total + 100;
 | 
						|
 | 
						|
    emit textChanged(tr("Installation finished!"));
 | 
						|
    emit progressChanged(total);
 | 
						|
    emit finished();
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::setupComponent(Component component)
 | 
						|
{
 | 
						|
    QString name;
 | 
						|
    switch (component) {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        name = QLatin1String("Morrowind");
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        name = QLatin1String("Tribunal");
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        name = QLatin1String("Bloodmoon");
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (name.isEmpty()) {
 | 
						|
        emit error(tr("Component parameter is invalid!"), tr("An invalid component parameter was supplied."));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    bool found = false;
 | 
						|
    QString cabFile;
 | 
						|
    QDir disk;
 | 
						|
 | 
						|
    // Keep showing the file dialog until we find the necessary install files
 | 
						|
    while (!found) {
 | 
						|
        if (getDiskPath().isEmpty()) {
 | 
						|
            QReadLocker readLock(&mLock);
 | 
						|
            emit requestFileDialog(component);
 | 
						|
            mWait.wait(&mLock);
 | 
						|
            disk.setPath(getDiskPath());
 | 
						|
        } else {
 | 
						|
            disk.setPath(getDiskPath());
 | 
						|
        }
 | 
						|
 | 
						|
        QStringList list(findFiles(QLatin1String("data1.hdr"), disk.absolutePath()));
 | 
						|
 | 
						|
        foreach (const QString &file, list) {
 | 
						|
 | 
						|
            qDebug() << "current archive: " << file;
 | 
						|
 | 
						|
            if (component == Wizard::Component_Morrowind)
 | 
						|
            {
 | 
						|
                bool morrowindFound = findInCab(QLatin1String("Morrowind.bsa"), file);
 | 
						|
                bool tribunalFound = findInCab(QLatin1String("Tribunal.bsa"), file);
 | 
						|
                bool bloodmoonFound = findInCab(QLatin1String("Bloodmoon.bsa"), file);
 | 
						|
 | 
						|
                if (morrowindFound) {
 | 
						|
                    // Check if we have correct archive, other archives have Morrowind.bsa too
 | 
						|
                    if ((tribunalFound && bloodmoonFound)
 | 
						|
                            || (!tribunalFound && !bloodmoonFound)) {
 | 
						|
                        cabFile = file;
 | 
						|
                        found = true; // We have a GoTY disk or a Morrowind-only disk
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
 | 
						|
                if (findInCab(name + QLatin1String(".bsa"), file)) {
 | 
						|
                    cabFile = file;
 | 
						|
                    found = true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        if (!found) {
 | 
						|
            QReadLocker readLock(&mLock);
 | 
						|
            emit requestFileDialog(component);
 | 
						|
            mWait.wait(&mLock);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (installComponent(component, cabFile)) {
 | 
						|
        setComponentDone(component, true);
 | 
						|
        return true;
 | 
						|
    } else {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::installComponent(Component component, const QString &path)
 | 
						|
{
 | 
						|
    QString name;
 | 
						|
    switch (component) {
 | 
						|
 | 
						|
    case Wizard::Component_Morrowind:
 | 
						|
        name = QLatin1String("Morrowind");
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Tribunal:
 | 
						|
        name = QLatin1String("Tribunal");
 | 
						|
        break;
 | 
						|
    case Wizard::Component_Bloodmoon:
 | 
						|
        name = QLatin1String("Bloodmoon");
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (name.isEmpty()) {
 | 
						|
        emit error(tr("Component parameter is invalid!"), tr("An invalid component parameter was supplied."));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    emit textChanged(tr("Installing %1").arg(name));
 | 
						|
 | 
						|
    QFileInfo info(path);
 | 
						|
 | 
						|
    if (!info.exists()) {
 | 
						|
        emit error(tr("Installation media path not set!"), tr("The source path for %1 was not set.").arg(name));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // Create temporary extract directory
 | 
						|
    // TODO: Use QTemporaryDir in Qt 5.0
 | 
						|
    QString tempPath(getPath() + QDir::separator() + QLatin1String("extract-temp"));
 | 
						|
    QDir temp;
 | 
						|
 | 
						|
    // Make sure the temporary folder is empty
 | 
						|
    removeDirectory(tempPath);
 | 
						|
 | 
						|
    if (!temp.mkpath(tempPath)) {
 | 
						|
        emit error(tr("Cannot create temporary directory!"), tr("Failed to create %1.").arg(tempPath));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    temp.setPath(tempPath);
 | 
						|
 | 
						|
    if (!temp.mkdir(name)) {
 | 
						|
        emit error(tr("Cannot create temporary directory!"), tr("Failed to create %1.").arg(temp.absoluteFilePath(name)));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!temp.cd(name)) {
 | 
						|
        emit error(tr("Cannot move into temporary directory!"), tr("Failed to move into %1.").arg(temp.absoluteFilePath(name)));
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // Extract the installation files
 | 
						|
    if (!extractCab(info.absoluteFilePath(), temp.absolutePath()))
 | 
						|
        return false;
 | 
						|
 | 
						|
    // Move the files from the temporary path to the destination folder
 | 
						|
    emit textChanged(tr("Moving installation files"));
 | 
						|
 | 
						|
    // Install extracted directories
 | 
						|
    QStringList directories;
 | 
						|
    directories << QLatin1String("BookArt")
 | 
						|
                << QLatin1String("Fonts")
 | 
						|
                << QLatin1String("Icons")
 | 
						|
                << QLatin1String("Meshes")
 | 
						|
                << QLatin1String("Music")
 | 
						|
                << QLatin1String("Sound")
 | 
						|
                << QLatin1String("Splash")
 | 
						|
                << QLatin1String("Textures")
 | 
						|
                << QLatin1String("Video");
 | 
						|
 | 
						|
    foreach (const QString &dir, directories) {
 | 
						|
        if (!installDirectories(dir, temp.absolutePath())) {
 | 
						|
            emit error(tr("Could not install directory!"),
 | 
						|
                       tr("Installing %1 to %2 failed.").arg(dir, temp.absolutePath()));
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Install directories from disk
 | 
						|
    foreach (const QString &dir, directories) {
 | 
						|
        if (!installDirectories(dir, info.absolutePath(), false, true)) {
 | 
						|
            emit error(tr("Could not install directory!"),
 | 
						|
                       tr("Installing %1 to %2 failed.").arg(dir, info.absolutePath()));
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    // Install translation files
 | 
						|
    QStringList extensions;
 | 
						|
    extensions << QLatin1String(".cel")
 | 
						|
               << QLatin1String(".top")
 | 
						|
               << QLatin1String(".mrk");
 | 
						|
 | 
						|
    foreach (const QString &extension, extensions) {
 | 
						|
        if (!installFiles(extension, info.absolutePath(), Qt::MatchEndsWith)) {
 | 
						|
            emit error(tr("Could not install translation file!"),
 | 
						|
                       tr("Failed to install *%1 files.").arg(extension));
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (component == Wizard::Component_Morrowind)
 | 
						|
    {
 | 
						|
        QStringList files;
 | 
						|
        files << QLatin1String("Morrowind.esm")
 | 
						|
              << QLatin1String("Morrowind.bsa");
 | 
						|
 | 
						|
        foreach (const QString &file, files) {
 | 
						|
            if (!installFile(file, temp.absolutePath())) {
 | 
						|
                emit error(tr("Could not install Morrowind data file!"),
 | 
						|
                           tr("Failed to install %1.").arg(file));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Copy Morrowind configuration file
 | 
						|
        if (!installFile(QLatin1String("Morrowind.ini"), temp.absolutePath())) {
 | 
						|
            emit error(tr("Could not install Morrowind configuration file!"),
 | 
						|
                       tr("Failed to install %1.").arg(QLatin1String("Morrowind.ini")));
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Setup Morrowind configuration
 | 
						|
        setIniPath(getPath() + QDir::separator() + QLatin1String("Morrowind.ini"));
 | 
						|
 | 
						|
        if (!setupSettings())
 | 
						|
            return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (component == Wizard::Component_Tribunal)
 | 
						|
    {
 | 
						|
        QFileInfo sounds(temp.absoluteFilePath(QLatin1String("Sounds")));
 | 
						|
        QString dest(getPath() + QDir::separator() + QLatin1String("Sound"));
 | 
						|
 | 
						|
        if (sounds.exists()) {
 | 
						|
            emit textChanged(tr("Installing: Sound directory"));
 | 
						|
            if (!copyDirectory(sounds.absoluteFilePath(), dest)) {
 | 
						|
                emit error(tr("Could not install directory!"),
 | 
						|
                           tr("Installing %1 to %2 failed.").arg(sounds.absoluteFilePath(), dest));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        QStringList files;
 | 
						|
        files << QLatin1String("Tribunal.esm")
 | 
						|
              << QLatin1String("Tribunal.bsa");
 | 
						|
 | 
						|
        foreach (const QString &file, files) {
 | 
						|
            if (!installFile(file, temp.absolutePath())) {
 | 
						|
                emit error(tr("Could not find Tribunal data file!"),
 | 
						|
                           tr("Failed to find %1.").arg(file));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (component == Wizard::Component_Bloodmoon)
 | 
						|
    {
 | 
						|
        QFileInfo original(getPath() + QDir::separator() + QLatin1String("Tribunal.esm"));
 | 
						|
 | 
						|
        if (original.exists()) {
 | 
						|
            if (!installFile(QLatin1String("Tribunal.esm"), temp.absolutePath())) {
 | 
						|
                emit error(tr("Could not find Tribunal patch file!"),
 | 
						|
                           tr("Failed to find %1.").arg(QLatin1String("Tribunal.esm")));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        QStringList files;
 | 
						|
        files << QLatin1String("Bloodmoon.esm")
 | 
						|
              << QLatin1String("Bloodmoon.bsa");
 | 
						|
 | 
						|
        foreach (const QString &file, files) {
 | 
						|
            if (!installFile(file, temp.absolutePath())) {
 | 
						|
                emit error(tr("Could not find Bloodmoon data file!"),
 | 
						|
                           tr("Failed to find %1.").arg(file));
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Load Morrowind configuration settings from the setup script
 | 
						|
        QStringList list(findFiles(QLatin1String("setup.inx"), getDiskPath()));
 | 
						|
 | 
						|
        emit textChanged(tr("Updating Morrowind configuration file"));
 | 
						|
 | 
						|
        foreach (const QString &inx, list) {
 | 
						|
             mIniSettings.parseInx(inx);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Finally, install Data Files directories from temp and disk
 | 
						|
    QStringList datafiles(findDirectories(QLatin1String("Data Files"), temp.absolutePath()));
 | 
						|
    datafiles.append(findDirectories(QLatin1String("Data Files"), info.absolutePath()));
 | 
						|
 | 
						|
    foreach (const QString &dir, datafiles) {
 | 
						|
        QFileInfo info(dir);
 | 
						|
        emit textChanged(tr("Installing: %1 directory").arg(info.fileName()));
 | 
						|
 | 
						|
        if (!copyDirectory(info.absoluteFilePath(), getPath())) {
 | 
						|
            emit error(tr("Could not install directory!"),
 | 
						|
                       tr("Installing %1 to %2 failed.").arg(info.absoluteFilePath(), getPath()));
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    emit textChanged(tr("%1 installation finished!").arg(name));
 | 
						|
    return true;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::extractFile(Unshield *unshield, const QString &destination, const QString &prefix, int index, int counter)
 | 
						|
{
 | 
						|
    bool success = false;
 | 
						|
    QString path(destination);
 | 
						|
    path.append(QDir::separator());
 | 
						|
 | 
						|
    int directory = unshield_file_directory(unshield, index);
 | 
						|
 | 
						|
    if (!prefix.isEmpty())
 | 
						|
        path.append(prefix + QDir::separator());
 | 
						|
 | 
						|
    if (directory >= 0)
 | 
						|
        path.append(QString::fromUtf8(unshield_directory_name(unshield, directory)) + QDir::separator());
 | 
						|
 | 
						|
    // Ensure the path has the right separators
 | 
						|
    path.replace(QLatin1Char('\\'), QDir::separator());
 | 
						|
    path = QDir::toNativeSeparators(path);
 | 
						|
 | 
						|
    // Ensure the target path exists
 | 
						|
    QDir dir;
 | 
						|
    if (!dir.mkpath(path))
 | 
						|
        return false;
 | 
						|
 | 
						|
    QString fileName(path);
 | 
						|
    fileName.append(QString::fromUtf8(unshield_file_name(unshield, index)));
 | 
						|
 | 
						|
    // Calculate the percentage done
 | 
						|
    int progress = (((float) counter / (float) unshield_file_count(unshield)) * 100);
 | 
						|
 | 
						|
    if (getComponentDone(Wizard::Component_Morrowind))
 | 
						|
        progress = progress + 100;
 | 
						|
 | 
						|
    if (getComponentDone(Wizard::Component_Tribunal))
 | 
						|
        progress = progress + 100;
 | 
						|
 | 
						|
    emit textChanged(tr("Extracting: %1").arg(QString::fromUtf8(unshield_file_name(unshield, index))));
 | 
						|
    emit progressChanged(progress);
 | 
						|
 | 
						|
    QByteArray array(fileName.toUtf8());
 | 
						|
    success = unshield_file_save(unshield, index, array.constData());
 | 
						|
 | 
						|
    if (!success) {
 | 
						|
        qDebug() << "error";
 | 
						|
        dir.remove(fileName);
 | 
						|
    }
 | 
						|
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::extractCab(const QString &cabFile, const QString &destination)
 | 
						|
{
 | 
						|
    bool success = false;
 | 
						|
 | 
						|
    QByteArray array(cabFile.toUtf8());
 | 
						|
 | 
						|
    Unshield *unshield;
 | 
						|
    unshield = unshield_open(array.constData());
 | 
						|
 | 
						|
    if (!unshield) {
 | 
						|
        emit error(tr("Failed to open InstallShield Cabinet File."), tr("Opening %1 failed.").arg(cabFile));
 | 
						|
        unshield_close(unshield);
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    int counter = 0;
 | 
						|
 | 
						|
    for (int i=0; i<unshield_file_group_count(unshield); ++i)
 | 
						|
    {
 | 
						|
        UnshieldFileGroup *group = unshield_file_group_get(unshield, i);
 | 
						|
 | 
						|
        for (size_t j=group->first_file; j<=group->last_file; ++j)
 | 
						|
        {
 | 
						|
            if (mStopped) {
 | 
						|
                qDebug() << "We're asked to stop!";
 | 
						|
 | 
						|
                unshield_close(unshield);
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
 | 
						|
            if (unshield_file_is_valid(unshield, j)) {
 | 
						|
                success = extractFile(unshield, destination, group->name, j, counter);
 | 
						|
 | 
						|
                if (!success) {
 | 
						|
                    QString name(QString::fromUtf8(unshield_file_name(unshield, j)));
 | 
						|
 | 
						|
                    emit error(tr("Failed to extract %1.").arg(name),
 | 
						|
                               tr("Complete path: %1").arg(destination + QDir::separator() + name));
 | 
						|
 | 
						|
                    unshield_close(unshield);
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
 | 
						|
                ++counter;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    unshield_close(unshield);
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
QString Wizard::UnshieldWorker::findFile(const QString &fileName, const QString &path)
 | 
						|
{
 | 
						|
    return findFiles(fileName, path).first();
 | 
						|
}
 | 
						|
 | 
						|
QStringList Wizard::UnshieldWorker::findFiles(const QString &fileName, const QString &path, int depth, bool recursive,
 | 
						|
                                              bool directories, Qt::MatchFlags flags)
 | 
						|
{
 | 
						|
    static const int MAXIMUM_DEPTH = 10;
 | 
						|
 | 
						|
    if (depth >= MAXIMUM_DEPTH) {
 | 
						|
        qWarning("Maximum directory depth limit reached.");
 | 
						|
        return QStringList();
 | 
						|
    }
 | 
						|
 | 
						|
    QStringList result;
 | 
						|
    QDir dir(path);
 | 
						|
 | 
						|
    // Prevent parsing over the complete filesystem
 | 
						|
    if (dir == QDir::rootPath())
 | 
						|
        return QStringList();
 | 
						|
 | 
						|
    if (!dir.exists())
 | 
						|
        return QStringList();
 | 
						|
 | 
						|
    QFileInfoList list(dir.entryInfoList(QDir::NoDotAndDotDot |
 | 
						|
                                         QDir::AllDirs | QDir::Files, QDir::DirsFirst));
 | 
						|
    foreach(QFileInfo info, list) {
 | 
						|
        if (info.isSymLink())
 | 
						|
            continue;
 | 
						|
 | 
						|
        if (info.isDir()) {
 | 
						|
            if (directories)
 | 
						|
            {
 | 
						|
                if (info.fileName() == fileName) {
 | 
						|
                    result.append(info.absoluteFilePath());
 | 
						|
                } else {
 | 
						|
                    if (recursive)
 | 
						|
                        result.append(findFiles(fileName, info.absoluteFilePath(), depth + 1, recursive, true));
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                if (recursive)
 | 
						|
                    result.append(findFiles(fileName, info.absoluteFilePath(), depth + 1));
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            if (directories)
 | 
						|
                break;
 | 
						|
 | 
						|
            switch (flags) {
 | 
						|
            case Qt::MatchExactly:
 | 
						|
                if (info.fileName() == fileName)
 | 
						|
                    result.append(info.absoluteFilePath());
 | 
						|
                break;
 | 
						|
            case Qt::MatchEndsWith:
 | 
						|
                if (info.fileName().endsWith(fileName))
 | 
						|
                    result.append(info.absoluteFilePath());
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
QStringList Wizard::UnshieldWorker::findDirectories(const QString &dirName, const QString &path, bool recursive)
 | 
						|
{
 | 
						|
    return findFiles(dirName, path, 0, true, true);
 | 
						|
}
 | 
						|
 | 
						|
bool Wizard::UnshieldWorker::findInCab(const QString &fileName, const QString &cabFile)
 | 
						|
{
 | 
						|
    QByteArray array(cabFile.toUtf8());
 | 
						|
 | 
						|
    Unshield *unshield;
 | 
						|
    unshield = unshield_open(array.constData());
 | 
						|
 | 
						|
    if (!unshield) {
 | 
						|
        emit error(tr("Failed to open InstallShield Cabinet File."), tr("Opening %1 failed.").arg(cabFile));
 | 
						|
        unshield_close(unshield);
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    for (int i=0; i<unshield_file_group_count(unshield); ++i)
 | 
						|
    {
 | 
						|
        UnshieldFileGroup *group = unshield_file_group_get(unshield, i);
 | 
						|
 | 
						|
        for (size_t j=group->first_file; j<=group->last_file; ++j)
 | 
						|
        {
 | 
						|
 | 
						|
            if (unshield_file_is_valid(unshield, j)) {
 | 
						|
                QString current(QString::fromUtf8(unshield_file_name(unshield, j)));
 | 
						|
                if (current.toLower() == fileName.toLower()) {
 | 
						|
                    unshield_close(unshield);
 | 
						|
                    return true; // File is found!
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    unshield_close(unshield);
 | 
						|
    return false;
 | 
						|
}
 |