1 #include "inisettings.hpp"
2
3 #include <QTextStream>
4 #include <QFile>
5 #include <QStringList>
6 #include <QString>
7 #include <QRegExp>
8 #include <QDebug>
9
IniSettings()10 Wizard::IniSettings::IniSettings()
11 {
12 }
13
~IniSettings()14 Wizard::IniSettings::~IniSettings()
15 {
16 }
17
findKeys(const QString & text)18 QStringList Wizard::IniSettings::findKeys(const QString &text)
19 {
20 QStringList result;
21
22 for (const QString &key : mSettings.keys())
23 {
24
25 if (key.startsWith(text))
26 result << key;
27
28 }
29
30 return result;
31 }
32
readFile(QTextStream & stream)33 bool Wizard::IniSettings::readFile(QTextStream &stream)
34 {
35 // Look for a square bracket, "'\\["
36 // that has one or more "not nothing" in it, "([^]]+)"
37 // and is closed with a square bracket, "\\]"
38 QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
39
40 // Find any character(s) that is/are not equal sign(s), "[^=]+"
41 // followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
42 // and one or more periods, "(.+)"
43 QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
44
45 QString currentSection;
46
47 while (!stream.atEnd())
48 {
49 const QString line(stream.readLine());
50
51 if (line.isEmpty() || line.startsWith(QLatin1Char(';')))
52 continue;
53
54 if (sectionRe.exactMatch(line))
55 {
56 currentSection = sectionRe.cap(1);
57 }
58 else if (keyRe.indexIn(line) != -1)
59 {
60 QString key = keyRe.cap(1).trimmed();
61 QString value = keyRe.cap(2).trimmed();
62
63 // Append the section, but only if there is one
64 if (!currentSection.isEmpty())
65 key = currentSection + QLatin1Char('/') + key;
66
67 mSettings[key] = QVariant(value);
68 }
69 }
70
71 return true;
72 }
73
writeFile(const QString & path,QTextStream & stream)74 bool Wizard::IniSettings::writeFile(const QString &path, QTextStream &stream)
75 {
76 // Look for a square bracket, "'\\["
77 // that has one or more "not nothing" in it, "([^]]+)"
78 // and is closed with a square bracket, "\\]"
79 QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
80
81 // Find any character(s) that is/are not equal sign(s), "[^=]+"
82 // followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
83 // and one or more periods, "(.+)"
84 QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
85
86 const QStringList keys(mSettings.keys());
87
88 QString currentSection;
89 QString buffer;
90
91 while (!stream.atEnd()) {
92
93 const QString line(stream.readLine());
94
95 if (line.isEmpty() || line.startsWith(QLatin1Char(';'))) {
96 buffer.append(line + QLatin1String("\n"));
97 continue;
98 }
99
100 if (sectionRe.exactMatch(line)) {
101 buffer.append(line + QLatin1String("\n"));
102 currentSection = sectionRe.cap(1);
103 } else if (keyRe.indexIn(line) != -1) {
104 QString key(keyRe.cap(1).trimmed());
105 QString lookupKey(key);
106
107 // Append the section, but only if there is one
108 if (!currentSection.isEmpty())
109 lookupKey = currentSection + QLatin1Char('/') + key;
110
111 buffer.append(key + QLatin1Char('=') + mSettings[lookupKey].toString() + QLatin1String("\n"));
112 mSettings.remove(lookupKey);
113 }
114 }
115
116 // Add the new settings to the buffer
117 QHashIterator<QString, QVariant> i(mSettings);
118 while (i.hasNext()) {
119 i.next();
120
121 QStringList fullKey(i.key().split(QLatin1Char('/')));
122 QString section(fullKey.at(0));
123 section.prepend(QLatin1Char('['));
124 section.append(QLatin1Char(']'));
125 QString key(fullKey.at(1));
126
127 int index = buffer.lastIndexOf(section);
128 if (index == -1) {
129 // Add the section to the end of the file, because it's not found
130 buffer.append(QString("\n%1\n").arg(section));
131 index = buffer.lastIndexOf(section);
132 }
133
134 // Look for the next section
135 index = buffer.indexOf(QLatin1Char('['), index + 1);
136
137 if (index == -1 ) {
138 // We are at the last section, append it to the bottom of the file
139 buffer.append(QString("\n%1=%2").arg(key, i.value().toString()));
140 mSettings.remove(i.key());
141 continue;
142 } else {
143 // Not at last section, add the key at the index
144 buffer.insert(index - 1, QString("\n%1=%2").arg(key, i.value().toString()));
145 mSettings.remove(i.key());
146 }
147 }
148
149 // Now we reopen the file, this time we write
150 QFile file(path);
151
152 if (file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) {
153 QTextStream in(&file);
154 in.setCodec(stream.codec());
155
156 // Write the updated buffer to an empty file
157 in << buffer;
158 file.flush();
159 file.close();
160 } else {
161 return false;
162 }
163
164 return true;
165 }
166
parseInx(const QString & path)167 bool Wizard::IniSettings::parseInx(const QString &path)
168 {
169 QFile file(path);
170
171 if (file.open(QIODevice::ReadOnly))
172 {
173
174 const QByteArray data(file.readAll());
175 const QByteArray pattern("\x21\x00\x1A\x01\x04\x00\x04\x97\xFF\x06", 10);
176
177 int i = 0;
178 while ((i = data.indexOf(pattern, i)) != -1) {
179
180 int next = data.indexOf(pattern, i + 1);
181 if (next == -1)
182 break;
183
184 QByteArray array(data.mid(i, (next - i)));
185
186 // Skip some invalid entries
187 if (array.contains("\x04\x96\xFF")) {
188 ++i;
189 continue;
190 }
191
192 // Remove the pattern from the beginning
193 array.remove(0, 12);
194
195 int index = array.indexOf("\x06");
196 const QString section(array.left(index));
197
198 // Figure how many characters to read for the key
199 int length = array.indexOf("\x06", section.length() + 3) - (section.length() + 3);
200 const QString key(array.mid(section.length() + 3, length));
201
202 QString value(array.mid(section.length() + key.length() + 6));
203
204 // Add the value
205 setValue(section + QLatin1Char('/') + key, QVariant(value));
206
207 ++i;
208 }
209
210 file.close();
211 } else {
212 qDebug() << "Failed to open INX file: " << path;
213 return false;
214 }
215
216 return true;
217 }
218