cannam@3
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@3
|
2
|
cannam@3
|
3 #include "SimpleXMLRuleLoader.h"
|
cannam@4
|
4 #include "Rule.h"
|
cannam@7
|
5 #include "ImageAction.h"
|
cannam@8
|
6 #include "ExternalProcessAction.h"
|
cannam@12
|
7 #include "FDWriteAction.h"
|
cannam@3
|
8
|
cannam@3
|
9 #include <QFile>
|
cannam@3
|
10 #include <QIODevice>
|
cannam@3
|
11 #include <QXmlInputSource>
|
cannam@3
|
12
|
cannam@3
|
13 SimpleXMLRuleLoader::SimpleXMLRuleLoader() :
|
cannam@3
|
14 m_processor(0),
|
cannam@3
|
15 m_inPlugins(false),
|
cannam@7
|
16 m_inRules(false),
|
cannam@7
|
17 m_inRule(false),
|
cannam@7
|
18 m_rule(0)
|
cannam@3
|
19 {
|
cannam@3
|
20 }
|
cannam@3
|
21
|
cannam@3
|
22 bool
|
cannam@3
|
23 SimpleXMLRuleLoader::loadFile(Processor &processor, QString fileName)
|
cannam@3
|
24 {
|
cannam@3
|
25 QFile file(fileName);
|
cannam@3
|
26
|
cannam@3
|
27 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
cannam@3
|
28 std::cerr << "ERROR: SimpleXMLRuleLoader::load("
|
cannam@3
|
29 << fileName.toStdString()
|
cannam@3
|
30 << "): Failed to open file for reading" << std::endl;
|
cannam@3
|
31 return false;
|
cannam@3
|
32 }
|
cannam@3
|
33
|
cannam@3
|
34 QXmlInputSource source(&file);
|
cannam@3
|
35 return loadXml(processor, source);
|
cannam@3
|
36 }
|
cannam@3
|
37
|
cannam@3
|
38 bool
|
cannam@3
|
39 SimpleXMLRuleLoader::loadXml(Processor &processor, const QString &xmlData)
|
cannam@3
|
40 {
|
cannam@3
|
41 QXmlInputSource source;
|
cannam@3
|
42 source.setData(xmlData);
|
cannam@3
|
43 return loadXml(processor, source);
|
cannam@3
|
44 }
|
cannam@3
|
45
|
cannam@3
|
46 bool
|
cannam@3
|
47 SimpleXMLRuleLoader::loadXml(Processor &processor, QXmlInputSource &source)
|
cannam@3
|
48 {
|
cannam@3
|
49 QXmlSimpleReader reader;
|
cannam@3
|
50 reader.setContentHandler(this);
|
cannam@3
|
51 reader.setErrorHandler(this);
|
cannam@3
|
52 m_processor = &processor;
|
cannam@3
|
53 return reader.parse(source);
|
cannam@3
|
54 m_processor = 0;
|
cannam@3
|
55 }
|
cannam@3
|
56
|
cannam@3
|
57 bool
|
cannam@3
|
58 SimpleXMLRuleLoader::startElement(const QString &namespaceURI,
|
cannam@3
|
59 const QString &localName,
|
cannam@3
|
60 const QString &qName,
|
cannam@3
|
61 const QXmlAttributes &atts)
|
cannam@3
|
62 {
|
cannam@3
|
63 QString name = qName.toLower();
|
cannam@3
|
64
|
cannam@3
|
65 if (name == "plugins") {
|
cannam@3
|
66 if (m_inPlugins) {
|
cannam@3
|
67 std::cerr << "ERROR: SimpleXMLRuleLoader: Nested plugins elements" << std::endl;
|
cannam@3
|
68 return false;
|
cannam@3
|
69 } else {
|
cannam@3
|
70 m_inPlugins = true;
|
cannam@3
|
71 }
|
cannam@3
|
72 } else if (name == "plugin") {
|
cannam@4
|
73 if (!m_inPlugins) {
|
cannam@4
|
74 std::cerr << "ERROR: SimpleXMLRuleLoader: Plugin outside plugins element" << std::endl;
|
cannam@4
|
75 return false;
|
cannam@4
|
76 }
|
cannam@3
|
77 int extIndex = atts.value("index").toInt();
|
cannam@4
|
78 if (m_externalInternalIndexMap.find(extIndex) !=
|
cannam@4
|
79 m_externalInternalIndexMap.end()) {
|
cannam@4
|
80 std::cerr << "ERROR: SimpleXMLRuleLoader: Duplicate plugin index "
|
cannam@4
|
81 << extIndex << std::endl;
|
cannam@4
|
82 return false;
|
cannam@4
|
83 }
|
cannam@3
|
84 QString id = atts.value("id");
|
cannam@3
|
85 int intIndex = m_processor->addPlugin(id);
|
cannam@3
|
86 if (!intIndex) {
|
cannam@3
|
87 std::cerr << "WARNING: SimpleXMLRuleLoader: Failed to load plugin \""
|
cannam@3
|
88 << id.toStdString() << "\"" << std::endl;
|
cannam@3
|
89 } else {
|
cannam@3
|
90 std::cerr << "INFO: SimpleXMLRuleLoader: Successfully loaded plugin \"" << id.toStdString() << "\" (internal index " << intIndex << ", external index " << extIndex << ")" << std::endl;
|
cannam@3
|
91 m_externalInternalIndexMap[extIndex] = intIndex;
|
cannam@3
|
92 }
|
cannam@3
|
93 } else if (name == "rules") {
|
cannam@3
|
94 if (m_inRules) {
|
cannam@3
|
95 std::cerr << "ERROR: SimpleXMLRuleLoader: Nested rules elements" << std::endl;
|
cannam@3
|
96 return false;
|
cannam@3
|
97 } else {
|
cannam@3
|
98 m_inRules = true;
|
cannam@3
|
99 }
|
cannam@4
|
100 } else if (name == "outputrule") {
|
cannam@4
|
101
|
cannam@4
|
102 if (!m_inRules) {
|
cannam@4
|
103 std::cerr << "ERROR: SimpleXMLRuleLoader: Rule outside rules element" << std::endl;
|
cannam@4
|
104 return false;
|
cannam@4
|
105 }
|
cannam@7
|
106 if (m_inRule) {
|
cannam@7
|
107 std::cerr << "ERROR: SimpleXMLRuleLoader: Nested output rules" << std::endl;
|
cannam@7
|
108 return false;
|
cannam@7
|
109 }
|
cannam@4
|
110
|
cannam@7
|
111 m_inRule = true;
|
cannam@7
|
112 m_rule = new Rule();
|
cannam@7
|
113
|
cannam@7
|
114 } else if (name == "condition") {
|
cannam@7
|
115
|
cannam@7
|
116 if (!m_inRule) {
|
cannam@7
|
117 std::cerr << "ERROR: SimpleXMLRuleLoader: Condition outside rule" << std::endl;
|
cannam@7
|
118 return false;
|
cannam@7
|
119 }
|
cannam@7
|
120
|
cannam@4
|
121 int extIndex = atts.value("pluginIndex").toInt();
|
cannam@4
|
122
|
cannam@4
|
123 if (m_externalInternalIndexMap.find(extIndex) ==
|
cannam@4
|
124 m_externalInternalIndexMap.end()) {
|
cannam@4
|
125 std::cerr << "ERROR: SimpleXMLRuleLoader: Unknown plugin index \""
|
cannam@4
|
126 << extIndex << "\" in rule" << std::endl;
|
cannam@4
|
127 return false;
|
cannam@4
|
128 }
|
cannam@4
|
129
|
cannam@4
|
130 int intIndex = m_externalInternalIndexMap[extIndex];
|
cannam@4
|
131
|
cannam@4
|
132 bool ok = false;
|
cannam@4
|
133 int outputNumber = atts.value("outputNumber").toInt(&ok);
|
cannam@4
|
134 if (!ok) outputNumber = 0;
|
cannam@4
|
135
|
cannam@4
|
136 QString condStr = atts.value("condition").toLower();
|
cannam@7
|
137 Condition::Type type(Condition::Present);
|
cannam@4
|
138
|
cannam@7
|
139 if (condStr == "present") type = Condition::Present;
|
cannam@7
|
140 else if (condStr == "equalto") type = Condition::EqualTo;
|
cannam@7
|
141 else if (condStr == "greaterthan") type = Condition::GreaterThan;
|
cannam@7
|
142 else if (condStr == "lessthan") type = Condition::LessThan;
|
cannam@7
|
143 else if (condStr == "gapgreaterthan") type = Condition::GapGreaterThan;
|
cannam@7
|
144 else if (condStr == "gaplessthan") type = Condition::GapLessThan;
|
cannam@7
|
145 else if (condStr == "notequalto") type = Condition::NotEqualTo;
|
cannam@7
|
146 else if (condStr == "changed") type = Condition::Changed;
|
cannam@4
|
147
|
cannam@4
|
148 float arg = atts.value("argument").toFloat(&ok);
|
cannam@4
|
149 if (!ok) arg = 0.f;
|
cannam@4
|
150
|
cannam@7
|
151 Condition condition(intIndex, outputNumber, type, arg);
|
cannam@4
|
152
|
cannam@7
|
153 m_rule->addCondition(condition);
|
cannam@4
|
154
|
cannam@7
|
155 } else if (name == "action") {
|
cannam@7
|
156
|
cannam@7
|
157 if (!m_inRule) {
|
cannam@7
|
158 std::cerr << "ERROR: SimpleXMLRuleLoader: Action outside rule" << std::endl;
|
cannam@7
|
159 return false;
|
cannam@7
|
160 }
|
cannam@7
|
161
|
cannam@7
|
162 QString type = atts.value("type").toLower();
|
cannam@7
|
163
|
cannam@7
|
164 if (type == "image") {
|
cannam@13
|
165 QString image = atts.value("image");
|
cannam@7
|
166 Action *action = new ImageAction(image);
|
cannam@9
|
167 m_rule->addAction(action);
|
cannam@7
|
168 std::cerr << "INFO: SimpleXMLRuleLoader: Added image action" << std::endl;
|
cannam@8
|
169 } else if (type == "process") {
|
cannam@8
|
170 QString process = atts.value("process").toLower();
|
cannam@8
|
171 QStringList args = atts.value("arguments").split(',');
|
cannam@8
|
172 Action *action = new ExternalProcessAction(process, args);
|
cannam@9
|
173 m_rule->addAction(action);
|
cannam@8
|
174 std::cerr << "INFO: SimpleXMLRuleLoader: Added external process action" << std::endl;
|
cannam@12
|
175 } else if (type == "fdwrite") {
|
cannam@12
|
176 QString file = atts.value("file");
|
cannam@12
|
177 QString data = atts.value("data");
|
cannam@12
|
178 bool togglePrevious = false;
|
cannam@12
|
179 if (atts.value("togglePrevious") == "true") {
|
cannam@12
|
180 togglePrevious = true;
|
cannam@12
|
181 }
|
cannam@12
|
182 Action *action = new FDWriteAction(file, data, togglePrevious);
|
cannam@12
|
183 m_rule->addAction(action);
|
cannam@12
|
184 std::cerr << "INFO: SimpleXMLRuleLoader: Added fd write action" << std::endl;
|
cannam@4
|
185 } else {
|
cannam@7
|
186 std::cerr << "WARNING: SimpleXMLRuleLoader: Unknown action type \""
|
cannam@7
|
187 << type.toStdString() << "\"" << std::endl;
|
cannam@4
|
188 }
|
cannam@4
|
189 }
|
cannam@3
|
190
|
cannam@3
|
191 return true;
|
cannam@3
|
192 }
|
cannam@3
|
193
|
cannam@3
|
194 bool
|
cannam@3
|
195 SimpleXMLRuleLoader::characters(const QString &s)
|
cannam@3
|
196 {
|
cannam@3
|
197 return true;
|
cannam@3
|
198 }
|
cannam@3
|
199
|
cannam@3
|
200 bool
|
cannam@3
|
201 SimpleXMLRuleLoader::endElement(const QString &namespaceURI,
|
cannam@3
|
202 const QString &localName,
|
cannam@3
|
203 const QString &qName)
|
cannam@3
|
204 {
|
cannam@3
|
205 QString name = qName.toLower();
|
cannam@3
|
206
|
cannam@4
|
207 if (name == "plugins") {
|
cannam@4
|
208
|
cannam@4
|
209 if (!m_inPlugins) {
|
cannam@4
|
210 std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of plugins element (trying to continue)" << std::endl;
|
cannam@4
|
211 }
|
cannam@4
|
212 m_inPlugins = false;
|
cannam@4
|
213
|
cannam@4
|
214 } else if (name == "rules") {
|
cannam@4
|
215
|
cannam@4
|
216 if (!m_inRules) {
|
cannam@4
|
217 std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of rules element (trying to continue)" << std::endl;
|
cannam@4
|
218 }
|
cannam@4
|
219 m_inRules = false;
|
cannam@7
|
220
|
cannam@7
|
221 } else if (name == "outputrule") {
|
cannam@7
|
222
|
cannam@7
|
223 if (!m_inRule) {
|
cannam@7
|
224 std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of outputRule element" << std::endl;
|
cannam@7
|
225 return false;
|
cannam@7
|
226 } else {
|
cannam@7
|
227 m_processor->addRule(m_rule);
|
cannam@7
|
228 }
|
cannam@7
|
229 m_inRule = false;
|
cannam@4
|
230 }
|
cannam@7
|
231
|
cannam@3
|
232 return true;
|
cannam@3
|
233 }
|
cannam@3
|
234
|
cannam@3
|
235 bool
|
cannam@3
|
236 SimpleXMLRuleLoader::error(const QXmlParseException &exception)
|
cannam@3
|
237 {
|
cannam@3
|
238 m_errorString =
|
cannam@3
|
239 QString("ERROR: SimpleXMLRuleLoader: %1 at line %2, column %3")
|
cannam@3
|
240 .arg(exception.message())
|
cannam@3
|
241 .arg(exception.lineNumber())
|
cannam@3
|
242 .arg(exception.columnNumber());
|
cannam@3
|
243 std::cerr << m_errorString.toLocal8Bit().data() << std::endl;
|
cannam@3
|
244 return QXmlDefaultHandler::error(exception);
|
cannam@3
|
245 }
|
cannam@3
|
246
|
cannam@3
|
247 bool
|
cannam@3
|
248 SimpleXMLRuleLoader::fatalError(const QXmlParseException &exception)
|
cannam@3
|
249 {
|
cannam@3
|
250 m_errorString =
|
cannam@3
|
251 QString("FATAL ERROR: SimpleXMLRuleLoader: %1 at line %2, column %3")
|
cannam@3
|
252 .arg(exception.message())
|
cannam@3
|
253 .arg(exception.lineNumber())
|
cannam@3
|
254 .arg(exception.columnNumber());
|
cannam@3
|
255 std::cerr << m_errorString.toLocal8Bit().data() << std::endl;
|
cannam@3
|
256 return QXmlDefaultHandler::fatalError(exception);
|
cannam@3
|
257 }
|
cannam@3
|
258
|