Wizard now writes valid Morrowind.ini files

pull/136/head
pvdk 11 years ago
parent e8170adde5
commit 6916c0bc94

@ -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…
Cancel
Save