mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 17:56:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			219 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "inisettings.hpp"
 | |
| 
 | |
| #include <QDir>
 | |
| 
 | |
| #include <QTextStream>
 | |
| #include <QFile>
 | |
| #include <QStringList>
 | |
| #include <QString>
 | |
| #include <QRegExp>
 | |
| #include <QDebug>
 | |
| 
 | |
| Wizard::IniSettings::IniSettings()
 | |
| {
 | |
| }
 | |
| 
 | |
| 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)
 | |
| {
 | |
|     // 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*(.+)$"));
 | |
| 
 | |
|     QString currentSection;
 | |
| 
 | |
|     while (!stream.atEnd())
 | |
|     {
 | |
|         const QString line(stream.readLine());
 | |
| 
 | |
|         if (line.isEmpty() || line.startsWith(QLatin1Char(';')))
 | |
|             continue;
 | |
| 
 | |
|         if (sectionRe.exactMatch(line))
 | |
|         {
 | |
|             currentSection = sectionRe.cap(1);
 | |
|         }
 | |
|         else if (keyRe.indexIn(line) != -1)
 | |
|         {
 | |
|             QString key = keyRe.cap(1).trimmed();
 | |
|             QString value = keyRe.cap(2).trimmed();
 | |
| 
 | |
|             // Append the section, but only if there is one
 | |
|             if (!currentSection.isEmpty())
 | |
|                 key = currentSection + QLatin1Char('/') + key;
 | |
| 
 | |
|             mSettings[key] = QVariant(value);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool Wizard::IniSettings::writeFile(const QString &path, QTextStream &stream)
 | |
| {
 | |
|     // 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;
 | |
| 
 | |
|     while (!stream.atEnd()) {
 | |
| 
 | |
|         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) {
 | |
|             // Look for the next section
 | |
|             index = buffer.indexOf(QLatin1Char('['), index + 1);
 | |
| 
 | |
|             if (index == -1 ) {
 | |
|                 // We are at the last section, append it to the bottom of the file
 | |
|                 buffer.append(QString("\n%1=%2").arg(key, i.value().toString()));
 | |
|                 mSettings.remove(i.key());
 | |
|                 continue;
 | |
|             } else {
 | |
|                 // Not at last section, 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 length = array.indexOf("\x06", section.length() + 3) - (section.length() + 3);
 | |
|             const QString key(array.mid(section.length() + 3, length));
 | |
| 
 | |
|             QString value(array.mid(section.length() + key.length() + 6));
 | |
| 
 | |
|             // Add the value
 | |
|             setValue(section + QLatin1Char('/') + key, QVariant(value));
 | |
| 
 | |
|             ++i;
 | |
|         }
 | |
| 
 | |
|         file.close();
 | |
|     } else {
 | |
|         qDebug() << "Failed to open INX file: " << path;
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 |