MythTV master
configuration.cpp
Go to the documentation of this file.
1
2// Program Name: configuration.cpp
3// Created : Feb. 12, 2007
4//
5// Purpose : Configuration file Class
6//
7// Copyright (c) 2007 David Blain <dblain@mythtv.org>
8//
9// Licensed under the GPL v2 or later, see LICENSE for details
10//
12
13#include "configuration.h"
14
15#include <unistd.h> // for fsync
16
17#include <iostream>
18
19#include <QDir>
20#include <QFile>
21#include <QTextStream>
22
23#include "mythlogging.h"
24#include "mythdb.h"
25#include "compat.h"
26
27
29{
30 QString pathName = m_path + '/' + m_fileName;
31 QFile file(pathName);
32 return file.exists();
33}
34
36{
37 QString pathName = m_path + '/' + m_fileName;
38
39 LOG(VB_GENERAL, LOG_DEBUG, QString("Loading %1").arg(pathName));
40
41 QFile file(pathName);
42
43 if (file.exists() && !m_fileName.isEmpty()) // Ignore empty filenames
44 {
45
46 if (!file.open(QIODevice::ReadOnly))
47 {
48 return false;
49 }
50
51#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
52 QString error;
53 int line = 0;
54 int column = 0;
55 bool success = m_config.setContent(&file, false, &error, &line, &column);
56
57 file.close();
58
59 if (!success)
60 {
61 LOG(VB_GENERAL, LOG_ERR,
62 QString("Error parsing: %1 at line: %2 column: %3")
63 .arg(pathName, QString::number(line), QString::number(column)));
64
65 LOG(VB_GENERAL, LOG_ERR, QString("Error Msg: %1").arg(error));
66 return false;
67 }
68#else
69 auto parseresult = m_config.setContent(&file);
70
71 file.close();
72
73 if (!parseresult)
74 {
75 LOG(VB_GENERAL, LOG_ERR,
76 QString("Error parsing: %1 at line: %2 column: %3")
77 .arg(pathName, QString::number(parseresult.errorLine),
78 QString::number(parseresult.errorColumn)));
79
80 LOG(VB_GENERAL, LOG_ERR, QString("Error Msg: %1").arg(parseresult.errorMessage));
81 return false;
82 }
83#endif
84
85 m_rootNode = m_config.namedItem("Configuration");
86 }
87 else
88 {
89 m_rootNode = m_config.createElement("Configuration");
90 m_config.appendChild(m_rootNode);
91 }
92
93 return true;
94}
95
97{
98 if (m_fileName.isEmpty()) // Special case. No file is created
99 {
100 return true;
101 }
102
103 QString pathName = m_path + '/' + m_fileName;
104 QString backupName = pathName + ".old";
105
106 LOG(VB_GENERAL, LOG_DEBUG, QString("Saving %1").arg(pathName));
107
108 QFile file(pathName + ".new");
109
110 if (!file.exists())
111 {
112 QDir directory(m_path);
113 if (!directory.exists() && !directory.mkdir(m_path))
114 {
115 LOG(VB_GENERAL, LOG_ERR, QString("Could not create %1").arg(m_path));
116 return false;
117 }
118 }
119
120 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
121 {
122 LOG(VB_GENERAL, LOG_ERR, QString("Could not open settings file %1 for writing").arg(file.fileName()));
123 return false;
124 }
125
126 {
127 QTextStream ts(&file);
128 m_config.save(ts, 2);
129 }
130
131 file.flush();
132 fsync(file.handle());
133 file.close();
134
135 bool success = true;
136 if (QFile::exists(pathName))
137 {
138 if (QFile::exists(backupName) && !QFile::remove(backupName)) // if true, rename will fail
139 {
140 LOG(VB_GENERAL, LOG_ERR, QString("Failed to remove '%1', cannot backup current settings").arg(backupName));
141 }
142 success = QFile::rename(pathName, backupName); // backup old settings in case it fails
143 }
144
145 if (success) // no settings to overwrite or settings backed up successfully
146 {
147 success = file.rename(pathName); // move new settings into target location
148 if (success)
149 {
150 if (QFile::exists(backupName) && !QFile::remove(backupName))
151 {
152 LOG(VB_GENERAL, LOG_WARNING, QString("Failed to remove '%1'").arg(backupName));
153 }
154 }
155 else if (QFile::exists(backupName) && !QFile::rename(backupName, pathName)) // !success &&
156 {
157 LOG(VB_GENERAL, LOG_ERR, QString("Failed to rename (restore) '%1").arg(backupName));
158 }
159 }
160
161 if (!success)
162 {
163 LOG(VB_GENERAL, LOG_ERR, QString("Could not save settings file %1").arg(pathName));
164 }
165
166 return success;
167}
168
169QDomNode XmlConfiguration::FindNode(const QString &setting, bool create)
170{
171 QStringList path = setting.split('/', Qt::SkipEmptyParts);
172 return FindNode(path, m_rootNode, create);
173}
174
175QDomNode XmlConfiguration::FindNode(QStringList &path, QDomNode &current, bool create)
176{
177 if (path.empty())
178 {
179 return current;
180 }
181
182 QString name = path.front();
183 path.pop_front();
184
185 QDomNode child = current.namedItem(name);
186
187 if (child.isNull())
188 {
189 if (!create)
190 {
191 path.clear();
192 }
193 else if (!current.isNull()) // && create
194 {
195 child = current.appendChild(m_config.createElement(name));
196 }
197 }
198
199 return FindNode(path, child, create);
200}
201
202QString XmlConfiguration::GetValue(const QString &setting)
203{
204 QDomNode node = FindNode(setting, false);
205 QDomText textNode;
206 // -=>TODO: This Always assumes firstChild is a Text Node... should change
207 if (!node.isNull())
208 {
209 textNode = node.firstChild().toText();
210 if (!textNode.isNull())
211 {
212 LOG(VB_GENERAL, LOG_DEBUG, QString("Got \"%1\" for \"%2\"").arg(textNode.nodeValue(), setting));
213
214 return textNode.nodeValue();
215 }
216 }
217
218 LOG(VB_GENERAL, LOG_DEBUG, QString("Using default for \"%1\"").arg(setting));
219 return {};
220}
221
222void XmlConfiguration::SetValue(const QString &setting, const QString& value)
223{
224 LOG(VB_GENERAL, LOG_DEBUG, QString("Setting \"%1\" to \"%2\"").arg(setting, value));
225
226 QDomNode node = FindNode(setting, true);
227
228 if (!node.isNull())
229 {
230 QDomText textNode;
231
232 if (node.hasChildNodes())
233 {
234 // -=>TODO: This Always assumes only child is a Text Node... should change
235 textNode = node.firstChild().toText();
236 textNode.setNodeValue(value);
237 }
238 else
239 {
240 textNode = m_config.createTextNode(value);
241 node.appendChild(textNode);
242 }
243 }
244}
245
246void XmlConfiguration::ClearValue(const QString &setting)
247{
248 LOG(VB_GENERAL, LOG_DEBUG, QString("clearing %1").arg(setting));
249 QDomNode node = FindNode(setting, false);
250 if (!node.isNull())
251 {
252 QDomNode parent = node.parentNode();
253 parent.removeChild(node);
254 while (parent.childNodes().count() == 0)
255 {
256 QDomNode next_parent = parent.parentNode();
257 next_parent.removeChild(parent);
258 parent = next_parent;
259 }
260 }
261}
QDomNode m_rootNode
Definition: configuration.h:48
QDomNode FindNode(const QString &setting, bool create)
QString GetValue(const QString &setting)
void SetValue(const QString &setting, bool value)
void ClearValue(const QString &setting)
QDomDocument m_config
Definition: configuration.h:47
#define fsync(FD)
Definition: compat.h:63
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
def error(message)
Definition: smolt.py:409
bool exists(str path)
Definition: xbmcvfs.py:51