Akonadi

xmlparser.cpp
1 /*
2  Copyright (c) 2017 Daniel Vrátil <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "xmlparser.h"
21 #include "nodetree.h"
22 
23 #include <QFile>
24 
25 #include <iostream>
26 
27 
28 #define qPrintableRef(x) reinterpret_cast<const char *>(x.unicode())
29 
30 XmlParser::XmlParser()
31 {
32 }
33 
34 XmlParser::~XmlParser()
35 {
36 }
37 
38 Node const *XmlParser::tree() const
39 {
40  return mTree.get();
41 }
42 
43 
44 bool XmlParser::parse(const QString &filename)
45 {
46  QFile file(filename);
47  if (!file.open(QIODevice::ReadOnly)) {
48  std::cerr << qPrintable(file.errorString());
49  return false;
50  }
51 
52  mReader.setDevice(&file);
53  while (!mReader.atEnd()) {
54  mReader.readNext();
55  if (mReader.isStartElement() && mReader.name() == QLatin1String("protocol")) {
56  if (!parseProtocol()) {
57  return false;
58  }
59  }
60  }
61 
62  return true;
63 }
64 
65 bool XmlParser::parseProtocol()
66 {
67  Q_ASSERT(mReader.name() == QLatin1String("protocol"));
68 
69  const auto attrs = mReader.attributes();
70  if (!attrs.hasAttribute(QLatin1String("version"))) {
71  printError(QStringLiteral("Missing \"version\" attribute in <protocol> tag!"));
72  return false;
73  }
74 
75  auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1String("version")).toInt());
76 
77  while (!mReader.atEnd() &&
78  !(mReader.isEndElement() && mReader.name() == QLatin1String("protocol")))
79  {
80  mReader.readNext();
81  if (mReader.isStartElement()) {
82  const auto elemName = mReader.name();
83  if (elemName == QLatin1String("class") ||
84  elemName == QLatin1String("command") ||
85  elemName == QLatin1String("response") ||
86  elemName == QLatin1String("notification"))
87  {
88  if (!parseCommand(documentNode.get())) {
89  return false;
90  }
91  } else {
92  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
93  return false;
94  }
95  }
96  }
97 
98  mTree = std::move(documentNode);
99 
100  return true;
101 }
102 
103 bool XmlParser::parseCommand(DocumentNode *documentNode)
104 {
105  const auto attrs = mReader.attributes();
106  if (!attrs.hasAttribute(QLatin1String("name"))) {
107  printError(QStringLiteral("Missing \"name\" attribute in command tag!"));
108  return false;
109  }
110 
111  auto classNode = new ClassNode(attrs.value(QLatin1String("name")).toString(),
112  ClassNode::elementNameToType(mReader.name()),
113  documentNode);
114  new CtorNode({}, classNode);
115 
116  while (!mReader.atEnd() &&
117  !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name())))
118  {
119  mReader.readNext();
120  if (mReader.isStartElement()) {
121  if (mReader.name() == QLatin1String("ctor")) {
122  if (!parseCtor(classNode)) {
123  return false;
124  }
125  } else if (mReader.name() == QLatin1String("enum")
126  || mReader.name() == QLatin1String("flag")) {
127  if (!parseEnum(classNode)) {
128  return false;
129  }
130  } else if (mReader.name() == QLatin1String("param")) {
131  if (!parseParam(classNode)) {
132  return false;
133  }
134  } else {
135  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
136  return false;
137  }
138  }
139  }
140 
141  return true;
142 }
143 
144 bool XmlParser::parseCtor(ClassNode *classNode)
145 {
147  while (!mReader.atEnd() &&
148  !(mReader.isEndElement() && (mReader.name() == QLatin1String("ctor"))))
149  {
150  mReader.readNext();
151  if (mReader.isStartElement()) {
152  if (mReader.name() == QLatin1String("arg")) {
153  const auto attrs = mReader.attributes();
154  const QString name = attrs.value(QLatin1String("name")).toString();
155  const QString def = attrs.value(QLatin1String("default")).toString();
156  args << CtorNode::Argument{ name, QString(), def };
157  } else {
158  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
159  return false;
160  }
161  }
162 
163  }
164  new CtorNode(args, classNode);
165 
166  return true;
167 }
168 
169 bool XmlParser::parseEnum(ClassNode *classNode)
170 {
171  const auto attrs = mReader.attributes();
172  if (!attrs.hasAttribute(QLatin1String("name"))) {
173  printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!"));
174  return false;
175  }
176 
177  auto enumNode = new EnumNode(attrs.value(QLatin1String("name")).toString(),
178  EnumNode::elementNameToType(mReader.name()),
179  classNode);
180 
181  while (!mReader.atEnd() &&
182  !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) {
183  mReader.readNext();
184  if (mReader.isStartElement()) {
185  if (mReader.name() == QLatin1String("value")) {
186  if (!parseEnumValue(enumNode)) {
187  return false;
188  }
189  } else {
190  printError(QStringLiteral("Invalid tag inside of enum/flag tag: ").append(mReader.name()));
191  return false;
192  }
193  }
194  }
195 
196  return true;
197 }
198 
199 bool XmlParser::parseEnumValue(EnumNode *enumNode)
200 {
201  Q_ASSERT(mReader.name() == QLatin1String("value"));
202 
203  const auto attrs = mReader.attributes();
204  if (!attrs.hasAttribute(QLatin1String("name"))) {
205  printError(QStringLiteral("Missing \"name\" attribute in <value> tag!"));
206  return false;
207  }
208 
209  auto valueNode = new EnumValueNode(attrs.value(QLatin1String("name")).toString(),
210  enumNode);
211  if (attrs.hasAttribute(QLatin1String("value"))) {
212  valueNode->setValue(attrs.value(QLatin1String("value")).toString());
213  }
214 
215  return true;
216 }
217 
218 
219 bool XmlParser::parseParam(ClassNode *classNode)
220 {
221  Q_ASSERT(mReader.name() == QLatin1String("param"));
222 
223  const auto attrs = mReader.attributes();
224  if (!attrs.hasAttribute(QLatin1String("name"))) {
225  printError(QStringLiteral("Missing \"name\" attribute in <param> tag!"));
226  return false;
227  }
228  if (!attrs.hasAttribute(QLatin1String("type"))) {
229  printError(QStringLiteral("Missing \"type\" attribute in <param> tag!"));
230  return false;
231  }
232 
233  const auto name = attrs.value(QLatin1String("name")).toString();
234  const auto type = attrs.value(QLatin1String("type")).toString();
235 
236  for (auto child : classNode->children()) {
237  if (child->type() == Node::Ctor) {
238  auto ctor = const_cast<CtorNode *>(static_cast<const CtorNode *>(child));
239  ctor->setArgumentType(name, type);
240  }
241  }
242 
243  auto paramNode = new PropertyNode(name, type, classNode);
244 
245  if (attrs.hasAttribute(QLatin1String("default"))) {
246  paramNode->setDefaultValue(attrs.value(QLatin1String("default")).toString());
247  }
248  if (attrs.hasAttribute(QLatin1String("readOnly"))) {
249  paramNode->setReadOnly(attrs.value(QLatin1String("readOnly")) == QLatin1String("true"));
250  }
251  if (attrs.hasAttribute(QLatin1String("asReference"))) {
252  paramNode->setAsReference(attrs.value(QLatin1String("asReference")) == QLatin1String("true"));
253  }
254 
255  while (!mReader.atEnd() &&
256  !(mReader.isEndElement() && mReader.name() == QLatin1String("param"))) {
257  mReader.readNext();
258  if (mReader.isStartElement()) {
259  if (mReader.name() == QLatin1String("setter")) {
260  if (!parseSetter(paramNode)) {
261  return false;
262  }
263  } else if (mReader.name() == QLatin1String("depends")) {
264  auto dependsAttrs = mReader.attributes();
265  if (!dependsAttrs.hasAttribute(QLatin1String("enum"))) {
266  printError(QStringLiteral("Missing \"enum\" attribute in <depends> tag!"));
267  return false;
268  }
269  if (!dependsAttrs.hasAttribute(QLatin1String("value"))) {
270  printError(QStringLiteral("Missing \"value\" attribute in <depends> tag!"));
271  return false;
272  }
273  paramNode->addDependency(dependsAttrs.value(QLatin1String("enum")).toString(),
274  dependsAttrs.value(QLatin1String("value")).toString());
275  } else {
276  printError(QStringLiteral("Unknown tag: ").append(mReader.name()));
277  return false;
278  }
279  }
280  }
281 
282  return true;
283 }
284 
285 bool XmlParser::parseSetter(PropertyNode *parent)
286 {
287  const auto attrs = mReader.attributes();
288  auto setter = new PropertyNode::Setter;
289  setter->name = attrs.value(QLatin1String("name")).toString();
290  setter->type = attrs.value(QLatin1String("type")).toString();
291 
292  while (!mReader.atEnd() &&
293  !(mReader.isEndElement() && mReader.name() == QLatin1String("setter"))) {
294  mReader.readNext();
295  if (mReader.isStartElement()) {
296  if (mReader.name() == QLatin1String("append")) {
297  setter->append = mReader.attributes().value(QLatin1String("name")).toString();
298  } else if (mReader.name() == QLatin1String("remove")) {
299  setter->remove = mReader.attributes().value(QLatin1String("name")).toString();
300  }
301  }
302  }
303 
304  parent->setSetter(setter);
305 
306  return true;
307 }
308 
309 
310 void XmlParser::printError(const QString &error)
311 {
312  std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber()
313  << ": " << qPrintable(error) << std::endl;
314 }
Type type(const QString &mimeType)
QString name(const QVariant &location)
Definition: item.h:44
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.