forked from teamnwah/openmw-tes3coop
Wizard now writes valid Morrowind.ini files
This commit is contained in:
parent
e8170adde5
commit
6916c0bc94
8 changed files with 262 additions and 20 deletions
|
@ -38,8 +38,7 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked()
|
|||
QString path(QDir::toNativeSeparators(info.absolutePath()));
|
||||
QList<QListWidgetItem*> items = installationsList->findItems(path, Qt::MatchExactly);
|
||||
|
||||
if (items.isEmpty())
|
||||
{
|
||||
if (items.isEmpty()) {
|
||||
// Path is not yet in the list, add it
|
||||
mWizard->addInstallation(path);
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "inisettings.hpp"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QDebug>
|
||||
|
@ -15,25 +17,40 @@ Wizard::IniSettings::~IniSettings()
|
|||
{
|
||||
}
|
||||
|
||||
QStringList Wizard::IniSettings::findKeys(const QString &text)
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
foreach (const QString &key, mSettings.keys()) {
|
||||
|
||||
if (key.startsWith(text))
|
||||
result << key;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Wizard::IniSettings::readFile(QTextStream &stream)
|
||||
{
|
||||
qDebug() << "readFile called!";
|
||||
// Look for a square bracket, "'\\["
|
||||
// that has one or more "not nothing" in it, "([^]]+)"
|
||||
// and is closed with a square bracket, "\\]"
|
||||
QRegExp sectionRe("^\\[([^]]+)\\]");
|
||||
QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
|
||||
|
||||
// Find any character(s) that is/are not equal sign(s), "[^=]+"
|
||||
// followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
|
||||
// and one or more periods, "(.+)"
|
||||
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
|
||||
QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
|
||||
|
||||
QString currentSection;
|
||||
|
||||
while (!stream.atEnd())
|
||||
{
|
||||
QString line(stream.readLine());
|
||||
const QString line(stream.readLine());
|
||||
|
||||
if (line.isEmpty() || line.startsWith(";"))
|
||||
if (line.isEmpty() || line.startsWith(QLatin1Char(';')))
|
||||
continue;
|
||||
|
||||
if (sectionRe.exactMatch(line))
|
||||
|
@ -49,6 +66,7 @@ bool Wizard::IniSettings::readFile(QTextStream &stream)
|
|||
if (!currentSection.isEmpty())
|
||||
key = currentSection + QLatin1Char('/') + key;
|
||||
|
||||
qDebug() << "adding: " << key << value;
|
||||
mSettings[key] = QVariant(value);
|
||||
}
|
||||
}
|
||||
|
@ -56,13 +74,161 @@ bool Wizard::IniSettings::readFile(QTextStream &stream)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Wizard::IniSettings::writeFile(QTextStream &stream)
|
||||
bool Wizard::IniSettings::writeFile(const QString &path, QTextStream &stream)
|
||||
{
|
||||
qDebug() << "test! " << stream.readAll();
|
||||
// Look for a square bracket, "'\\["
|
||||
// that has one or more "not nothing" in it, "([^]]+)"
|
||||
// and is closed with a square bracket, "\\]"
|
||||
QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
|
||||
|
||||
// Find any character(s) that is/are not equal sign(s), "[^=]+"
|
||||
// followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
|
||||
// and one or more periods, "(.+)"
|
||||
QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
|
||||
|
||||
const QStringList keys(mSettings.keys());
|
||||
|
||||
QString currentSection;
|
||||
QString buffer;
|
||||
|
||||
qDebug() << "Keys! " << keys;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
qDebug() << "test! " << stream.readLine();
|
||||
|
||||
const QString line(stream.readLine());
|
||||
|
||||
if (line.isEmpty() || line.startsWith(QLatin1Char(';'))) {
|
||||
buffer.append(line + QLatin1String("\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sectionRe.exactMatch(line)) {
|
||||
buffer.append(line + QLatin1String("\n"));
|
||||
currentSection = sectionRe.cap(1);
|
||||
} else if (keyRe.indexIn(line) != -1) {
|
||||
QString key(keyRe.cap(1).trimmed());
|
||||
QString lookupKey(key);
|
||||
|
||||
// Append the section, but only if there is one
|
||||
if (!currentSection.isEmpty())
|
||||
lookupKey = currentSection + QLatin1Char('/') + key;
|
||||
|
||||
buffer.append(key + QLatin1Char('=') + mSettings[lookupKey].toString() + QLatin1String("\n"));
|
||||
mSettings.remove(lookupKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new settings to the buffer
|
||||
QHashIterator<QString, QVariant> i(mSettings);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
||||
QStringList fullKey(i.key().split(QLatin1Char('/')));
|
||||
QString section(fullKey.at(0));
|
||||
section.prepend(QLatin1Char('['));
|
||||
section.append(QLatin1Char(']'));
|
||||
QString key(fullKey.at(1));
|
||||
|
||||
int index = buffer.lastIndexOf(section);
|
||||
if (index != -1) {
|
||||
// Append the new keys to the bottom of the section
|
||||
index = buffer.indexOf(QLatin1Char('['), index + 1);
|
||||
|
||||
if (index == -1 )
|
||||
{
|
||||
// Beginning of next section not found, we are at the last section
|
||||
if (buffer.lastIndexOf(QLatin1String("\n")) > (buffer.lastIndexOf(section) + section.length())) {
|
||||
// There is a newline after the section
|
||||
index = buffer.lastIndexOf(QLatin1String("\n")) - 1;
|
||||
buffer.insert(index - 2, QString("\n%1=%2").arg(key, i.value().toString()));
|
||||
mSettings.remove(i.key());
|
||||
continue;
|
||||
} else {
|
||||
// No newline found, or the last newline is before the last section
|
||||
// Append the key to the bottom of the file
|
||||
buffer.append(QString("\n%1=%2").arg(key, i.value().toString()));
|
||||
mSettings.remove(i.key());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the key at the index
|
||||
buffer.insert(index - 1, QString("\n%1=%2").arg(key, i.value().toString()));
|
||||
mSettings.remove(i.key());
|
||||
} else {
|
||||
// Add the section to the end of the file, because it's not found
|
||||
buffer.append(QString("\n%1\n").arg(section));
|
||||
i.previous();
|
||||
}
|
||||
}
|
||||
|
||||
// Now we reopen the file, this time we write
|
||||
QFile file(path);
|
||||
|
||||
if (file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
in.setCodec(stream.codec());
|
||||
|
||||
// Write the updated buffer to an empty file
|
||||
in << buffer;
|
||||
file.flush();
|
||||
file.close();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wizard::IniSettings::parseInx(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
|
||||
const QByteArray data(file.readAll());
|
||||
const QByteArray pattern("\x21\x00\x1A\x01\x04\x00\x04\x97\xFF\x06", 10);
|
||||
|
||||
int i = 0;
|
||||
while ((i = data.indexOf(pattern, i)) != -1) {
|
||||
|
||||
int next = data.indexOf(pattern, i + 1);
|
||||
if (next == -1)
|
||||
break;
|
||||
|
||||
QByteArray array(data.mid(i, (next - i)));
|
||||
|
||||
// Skip some invalid entries
|
||||
if (array.contains("\x04\x96\xFF")) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the pattern from the beginning
|
||||
array.remove(0, 12);
|
||||
|
||||
int index = array.indexOf("\x06");
|
||||
const QString section(array.left(index));
|
||||
|
||||
// Figure how many characters to read for the key
|
||||
int lenght = array.indexOf("\x06", section.length() + 3) - (section.length() + 3);
|
||||
const QString key(array.mid(section.length() + 3, lenght));
|
||||
|
||||
QString value(array.mid(section.length() + key.length() + 6));
|
||||
//qDebug() << section << key << value;
|
||||
|
||||
// Add the value
|
||||
setValue(section + QLatin1Char('/') + key, QVariant(value));
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
file.close();
|
||||
} else {
|
||||
qDebug() << "Failed to open INX file: " << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@ namespace Wizard
|
|||
return mSettings.value(key, defaultValue);
|
||||
}
|
||||
|
||||
inline QList<QVariant> values() const
|
||||
{
|
||||
return mSettings.values();
|
||||
}
|
||||
|
||||
inline void setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
mSettings.insert(key, value);
|
||||
|
@ -32,11 +37,17 @@ namespace Wizard
|
|||
mSettings.remove(key);
|
||||
}
|
||||
|
||||
QStringList findKeys(const QString &text);
|
||||
|
||||
bool readFile(QTextStream &stream);
|
||||
bool writeFile(QTextStream &stream);
|
||||
bool writeFile(const QString &path, QTextStream &stream);
|
||||
|
||||
bool parseInx(const QString &path);
|
||||
|
||||
private:
|
||||
|
||||
int getLastNewline(const QString &buffer, int from);
|
||||
|
||||
SettingsMap mSettings;
|
||||
};
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ void Wizard::InstallationPage::startInstallation()
|
|||
|
||||
// Set the location of the Morrowind.ini to update
|
||||
mUnshield->setIniPath(mWizard->mInstallations[path]->iniPath);
|
||||
mUnshield->setupSettings();
|
||||
}
|
||||
|
||||
// Set the installation target path
|
||||
|
|
|
@ -21,11 +21,6 @@ void Wizard::InstallationTargetPage::initializePage()
|
|||
QString path(QFile::decodeName(mCfgMgr.getUserDataPath().string().c_str()));
|
||||
path.append(QDir::separator() + QLatin1String("data"));
|
||||
|
||||
if (!QFile::exists(path)) {
|
||||
QDir dir;
|
||||
dir.mkpath(path);
|
||||
}
|
||||
|
||||
QDir dir(path);
|
||||
targetLineEdit->setText(QDir::toNativeSeparators(dir.absolutePath()));
|
||||
}
|
||||
|
@ -36,6 +31,13 @@ bool Wizard::InstallationTargetPage::validatePage()
|
|||
|
||||
qDebug() << "Validating path: " << path;
|
||||
|
||||
// TODO: Check writeability
|
||||
if (!QFile::exists(path)) {
|
||||
QDir dir;
|
||||
dir.mkpath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mWizard->findFiles(QLatin1String("Morrowind"), path)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Destination not empty"));
|
||||
|
|
|
@ -127,6 +127,7 @@ void Wizard::MainWizard::setupPages()
|
|||
setPage(Page_Conclusion, new ConclusionPage(this));
|
||||
setStartId(Page_Intro);
|
||||
}
|
||||
|
||||
void Wizard::MainWizard::accept()
|
||||
{
|
||||
writeSettings();
|
||||
|
|
|
@ -43,7 +43,6 @@ Wizard::UnshieldWorker::UnshieldWorker(QObject *parent) :
|
|||
|
||||
Wizard::UnshieldWorker::~UnshieldWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Wizard::UnshieldWorker::setInstallComponent(Wizard::Component component, bool install)
|
||||
|
@ -198,6 +197,29 @@ void Wizard::UnshieldWorker::setupSettings()
|
|||
mIniSettings.readFile(stream);
|
||||
}
|
||||
|
||||
void Wizard::UnshieldWorker::writeSettings()
|
||||
{
|
||||
if (getIniPath().isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(getIniPath());
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
qDebug() << "Error opening .ini file!";
|
||||
emit error(tr("Failed to open Morrowind configuration file!"),
|
||||
tr("Opening %1 failed: %2.").arg(getIniPath(), file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
bool Wizard::UnshieldWorker::removeDirectory(const QString &dirName)
|
||||
{
|
||||
bool result = true;
|
||||
|
@ -383,6 +405,32 @@ void Wizard::UnshieldWorker::extract()
|
|||
setupAddon(Wizard::Component_Bloodmoon);
|
||||
}
|
||||
|
||||
// Update Morrowind configuration
|
||||
if (getInstallComponent(Wizard::Component_Tribunal))
|
||||
{
|
||||
mIniSettings.setValue(QLatin1String("Archives/Archive0"), QVariant(QString("Tribunal.bsa")));
|
||||
mIniSettings.setValue(QLatin1String("Game Files/Game File1"), QVariant(QString("Tribunal.esm")));
|
||||
}
|
||||
|
||||
if (getInstallComponent(Wizard::Component_Bloodmoon))
|
||||
{
|
||||
mIniSettings.setValue(QLatin1String("Archives/Archive0"), QVariant(QString("Bloodmoon.bsa")));
|
||||
mIniSettings.setValue(QLatin1String("Game Files/Game File1"), QVariant(QString("Bloodmoon.esm")));
|
||||
}
|
||||
|
||||
if (getInstallComponent(Wizard::Component_Tribunal) &&
|
||||
getInstallComponent(Wizard::Component_Bloodmoon))
|
||||
{
|
||||
mIniSettings.setValue(QLatin1String("Archives/Archive0"), QVariant(QString("Tribunal.bsa")));
|
||||
mIniSettings.setValue(QLatin1String("Archives/Archive1"), QVariant(QString("Bloodmoon.bsa")));
|
||||
mIniSettings.setValue(QLatin1String("Game Files/Game File1"), QVariant(QString("Tribunal.esm")));
|
||||
mIniSettings.setValue(QLatin1String("Game Files/Game File2"), QVariant(QString("Bloodmoon.esm")));
|
||||
}
|
||||
|
||||
|
||||
// Write the settings to the Morrowind config file
|
||||
writeSettings();
|
||||
|
||||
// Remove the temporary directory
|
||||
removeDirectory(getPath() + QDir::separator() + QLatin1String("extract-temp"));
|
||||
|
||||
|
@ -554,6 +602,10 @@ bool Wizard::UnshieldWorker::installComponent(Component component)
|
|||
emit error(tr("Could not find Morrowind configuration file!"), tr("Failed to find %0.").arg(iniPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup Morrowind configuration
|
||||
setIniPath(getPath() + QDir::separator() + QLatin1String("Morrowind.ini"));
|
||||
setupSettings();
|
||||
}
|
||||
|
||||
if (component == Wizard::Component_Tribunal)
|
||||
|
@ -564,7 +616,6 @@ bool Wizard::UnshieldWorker::installComponent(Component component)
|
|||
emit textChanged(tr("Extracting: Sound directory"));
|
||||
copyDirectory(sounds.absoluteFilePath(), getPath() + QDir::separator() + QLatin1String("Sound"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (component == Wizard::Component_Bloodmoon)
|
||||
|
@ -577,6 +628,15 @@ bool Wizard::UnshieldWorker::installComponent(Component component)
|
|||
copyFile(patch.absoluteFilePath(), original.absoluteFilePath());
|
||||
}
|
||||
|
||||
// Load Morrowind configuration settings from the setup script
|
||||
QFileInfo inx(disk.absoluteFilePath(QLatin1String("setup.inx")));
|
||||
|
||||
if (inx.exists()) {
|
||||
emit textChanged(tr("Updating Morrowind configuration file"));
|
||||
mIniSettings.parseInx(inx.absoluteFilePath());
|
||||
} else {
|
||||
qDebug() << "setup.inx not found!";
|
||||
}
|
||||
}
|
||||
|
||||
emit textChanged(tr("%0 installation finished!").arg(name));
|
||||
|
@ -649,7 +709,7 @@ bool Wizard::UnshieldWorker::findFile(const QString &cabFile, const QString &fil
|
|||
{
|
||||
QString current(QString::fromLatin1(unshield_file_name(unshield, j)));
|
||||
|
||||
qDebug() << "File is: " << unshield_file_name(unshield, j);
|
||||
qDebug() << "File is: " << current;
|
||||
if (current == fileName)
|
||||
return true; // File is found!
|
||||
}
|
||||
|
|
|
@ -41,8 +41,12 @@ namespace Wizard
|
|||
|
||||
void setIniCodec(QTextCodec *codec);
|
||||
|
||||
void setupSettings();
|
||||
|
||||
private:
|
||||
|
||||
void writeSettings();
|
||||
|
||||
bool getInstallComponent(Component component);
|
||||
|
||||
QString getComponentPath(Component component);
|
||||
|
@ -58,8 +62,6 @@ namespace Wizard
|
|||
bool moveFile(const QString &source, const QString &destination);
|
||||
bool moveDirectory(const QString &source, const QString &destination);
|
||||
|
||||
void setupSettings();
|
||||
|
||||
bool extractCab(const QString &cabFile, const QString &outputDir);
|
||||
bool extractFile(Unshield *unshield, const QString &outputDir, const QString &prefix, int index, int counter);
|
||||
bool findFile(const QString &cabFile, const QString &fileName);
|
||||
|
|
Loading…
Reference in a new issue