Akonadi

xmlparser.cpp
1 /*
2  SPDX-FileCopyrightText: 2017 Daniel Vr├ítil <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "xmlparser.h"
8 #include "nodetree.h"
9 
10 #include <QFile>
11 
12 #include <iostream>
13 
14 #define qPrintableRef(x) reinterpret_cast<const char *>((x).unicode())
15 
16 XmlParser::XmlParser()
17 {
18 }
19 
20 XmlParser::~XmlParser()
21 {
22 }
23 
24 Node const *XmlParser::tree() const
25 {
26  return mTree.get();
27 }
28 
29 bool XmlParser::parse(const QString &filename)
30 {
31  QFile file(filename);
32  if (!file.open(QIODevice::ReadOnly)) {
33  std::cerr << qPrintable(file.errorString());
34  return false;
35  }
36 
37  mReader.setDevice(&file);
38  while (!mReader.atEnd()) {
39  mReader.readNext();
40  if (mReader.isStartElement() && mReader.name() == QLatin1String("protocol")) {
41  if (!parseProtocol()) {
42  return false;
43  }
44  }
45  }
46 
47  return true;
48 }
49 
50 bool XmlParser::parseProtocol()
51 {
52  Q_ASSERT(mReader.name() == QLatin1String("protocol"));
53 
54  const auto attrs = mReader.attributes();
55  if (!attrs.hasAttribute(QLatin1String("version"))) {
56  printError(QStringLiteral("Missing \"version\" attribute in <protocol> tag!"));
57  return false;
58  }
59 
60  auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1String("version")).toInt());
61 
62  while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("protocol"))) {
63  mReader.readNext();
64  if (mReader.isStartElement()) {
65  const auto elemName = mReader.name();
66  if (elemName == QLatin1String("class") || elemName == QLatin1String("command") || elemName == QLatin1String("response")
67  || elemName == QLatin1String("notification")) {
68  if (!parseCommand(documentNode.get())) {
69  return false;
70  }
71  } else {
72  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
73  return false;
74  }
75  }
76  }
77 
78  mTree = std::move(documentNode);
79 
80  return true;
81 }
82 
83 bool XmlParser::parseCommand(DocumentNode *documentNode)
84 {
85  const auto attrs = mReader.attributes();
86  if (!attrs.hasAttribute(QLatin1String("name"))) {
87  printError(QStringLiteral("Missing \"name\" attribute in command tag!"));
88  return false;
89  }
90 
91  auto classNode = new ClassNode(attrs.value(QLatin1String("name")).toString(), ClassNode::elementNameToType(mReader.name()), documentNode);
92  new CtorNode({}, classNode);
93 
94  while (!mReader.atEnd() && !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) {
95  mReader.readNext();
96  if (mReader.isStartElement()) {
97  if (mReader.name() == QLatin1String("ctor")) {
98  if (!parseCtor(classNode)) {
99  return false;
100  }
101  } else if (mReader.name() == QLatin1String("enum") || mReader.name() == QLatin1String("flag")) {
102  if (!parseEnum(classNode)) {
103  return false;
104  }
105  } else if (mReader.name() == QLatin1String("param")) {
106  if (!parseParam(classNode)) {
107  return false;
108  }
109  } else {
110  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
111  return false;
112  }
113  }
114  }
115 
116  return true;
117 }
118 
119 bool XmlParser::parseCtor(ClassNode *classNode)
120 {
122  while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1String("ctor")))) {
123  mReader.readNext();
124  if (mReader.isStartElement()) {
125  if (mReader.name() == QLatin1String("arg")) {
126  const auto attrs = mReader.attributes();
127  const QString name = attrs.value(QLatin1String("name")).toString();
128  const QString def = attrs.value(QLatin1String("default")).toString();
129  args << CtorNode::Argument{name, QString(), def};
130  } else {
131  printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
132  return false;
133  }
134  }
135  }
136  new CtorNode(args, classNode);
137 
138  return true;
139 }
140 
141 bool XmlParser::parseEnum(ClassNode *classNode)
142 {
143  const auto attrs = mReader.attributes();
144  if (!attrs.hasAttribute(QLatin1String("name"))) {
145  printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!"));
146  return false;
147  }
148 
149  auto enumNode = new EnumNode(attrs.value(QLatin1String("name")).toString(), EnumNode::elementNameToType(mReader.name()), classNode);
150 
151  while (!mReader.atEnd() && !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) {
152  mReader.readNext();
153  if (mReader.isStartElement()) {
154  if (mReader.name() == QLatin1String("value")) {
155  if (!parseEnumValue(enumNode)) {
156  return false;
157  }
158  } else {
159  printError(QStringLiteral("Invalid tag inside of enum/flag tag: ").append(mReader.name()));
160  return false;
161  }
162  }
163  }
164 
165  return true;
166 }
167 
168 bool XmlParser::parseEnumValue(EnumNode *enumNode)
169 {
170  Q_ASSERT(mReader.name() == QLatin1String("value"));
171 
172  const auto attrs = mReader.attributes();
173  if (!attrs.hasAttribute(QLatin1String("name"))) {
174  printError(QStringLiteral("Missing \"name\" attribute in <value> tag!"));
175  return false;
176  }
177 
178  auto valueNode = new EnumValueNode(attrs.value(QLatin1String("name")).toString(), enumNode);
179  if (attrs.hasAttribute(QLatin1String("value"))) {
180  valueNode->setValue(attrs.value(QLatin1String("value")).toString());
181  }
182 
183  return true;
184 }
185 
186 bool XmlParser::parseParam(ClassNode *classNode)
187 {
188  Q_ASSERT(mReader.name() == QLatin1String("param"));
189 
190  const auto attrs = mReader.attributes();
191  if (!attrs.hasAttribute(QLatin1String("name"))) {
192  printError(QStringLiteral("Missing \"name\" attribute in <param> tag!"));
193  return false;
194  }
195  if (!attrs.hasAttribute(QLatin1String("type"))) {
196  printError(QStringLiteral("Missing \"type\" attribute in <param> tag!"));
197  return false;
198  }
199 
200  const auto name = attrs.value(QLatin1String("name")).toString();
201  const auto type = attrs.value(QLatin1String("type")).toString();
202 
203  for (const auto child : classNode->children()) {
204  if (child->type() == Node::Ctor) {
205  auto ctor = const_cast<CtorNode *>(static_cast<const CtorNode *>(child));
206  ctor->setArgumentType(name, type);
207  }
208  }
209 
210  auto paramNode = new PropertyNode(name, type, classNode);
211 
212  if (attrs.hasAttribute(QLatin1String("default"))) {
213  paramNode->setDefaultValue(attrs.value(QLatin1String("default")).toString());
214  }
215  if (attrs.hasAttribute(QLatin1String("readOnly"))) {
216  paramNode->setReadOnly(attrs.value(QLatin1String("readOnly")) == QLatin1String("true"));
217  }
218  if (attrs.hasAttribute(QLatin1String("asReference"))) {
219  paramNode->setAsReference(attrs.value(QLatin1String("asReference")) == QLatin1String("true"));
220  }
221 
222  while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("param"))) {
223  mReader.readNext();
224  if (mReader.isStartElement()) {
225  if (mReader.name() == QLatin1String("setter")) {
226  if (!parseSetter(paramNode)) {
227  return false;
228  }
229  } else if (mReader.name() == QLatin1String("depends")) {
230  auto dependsAttrs = mReader.attributes();
231  if (!dependsAttrs.hasAttribute(QLatin1String("enum"))) {
232  printError(QStringLiteral("Missing \"enum\" attribute in <depends> tag!"));
233  return false;
234  }
235  if (!dependsAttrs.hasAttribute(QLatin1String("value"))) {
236  printError(QStringLiteral("Missing \"value\" attribute in <depends> tag!"));
237  return false;
238  }
239  paramNode->addDependency(dependsAttrs.value(QLatin1String("enum")).toString(), dependsAttrs.value(QLatin1String("value")).toString());
240  } else {
241  printError(QStringLiteral("Unknown tag: ").append(mReader.name()));
242  return false;
243  }
244  }
245  }
246 
247  return true;
248 }
249 
250 bool XmlParser::parseSetter(PropertyNode *parent)
251 {
252  const auto attrs = mReader.attributes();
253  auto setter = new PropertyNode::Setter;
254  setter->name = attrs.value(QLatin1String("name")).toString();
255  setter->type = attrs.value(QLatin1String("type")).toString();
256 
257  while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("setter"))) {
258  mReader.readNext();
259  if (mReader.isStartElement()) {
260  if (mReader.name() == QLatin1String("append")) {
261  setter->append = mReader.attributes().value(QLatin1String("name")).toString();
262  } else if (mReader.name() == QLatin1String("remove")) {
263  setter->remove = mReader.attributes().value(QLatin1String("name")).toString();
264  }
265  }
266  }
267 
268  parent->setSetter(setter);
269 
270  return true;
271 }
272 
273 void XmlParser::printError(const QString &error)
274 {
275  std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber() << ": " << qPrintable(error) << std::endl;
276 }
char * toString(const T &value)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
Definition: nodetree.h:12
QString name(StandardShortcut id)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jul 2 2022 06:41:49 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.