Akonadi

xmlparser.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
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
16XmlParser::XmlParser()
17{
18}
19
20XmlParser::~XmlParser()
21{
22}
23
24Node const *XmlParser::tree() const
25{
26 return mTree.get();
27}
28
29bool 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() == QLatin1StringView("protocol")) {
41 if (!parseProtocol()) {
42 return false;
43 }
44 }
45 }
46
47 return true;
48}
49
50bool XmlParser::parseProtocol()
51{
52 Q_ASSERT(mReader.name() == QLatin1StringView("protocol"));
53
54 const auto attrs = mReader.attributes();
55 if (!attrs.hasAttribute(QLatin1StringView("version"))) {
56 printError(QStringLiteral("Missing \"version\" attribute in <protocol> tag!"));
57 return false;
58 }
59
60 auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1StringView("version")).toInt());
61
62 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("protocol"))) {
63 mReader.readNext();
64 if (mReader.isStartElement()) {
65 const auto elemName = mReader.name();
66 if (elemName == QLatin1StringView("class") || elemName == QLatin1StringView("command") || elemName == QLatin1StringView("response")
67 || elemName == QLatin1StringView("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
83bool XmlParser::parseCommand(DocumentNode *documentNode)
84{
85 const auto attrs = mReader.attributes();
86 if (!attrs.hasAttribute(QLatin1StringView("name"))) {
87 printError(QStringLiteral("Missing \"name\" attribute in command tag!"));
88 return false;
89 }
90
91 auto classNode = new ClassNode(attrs.value(QLatin1StringView("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() == QLatin1StringView("ctor")) {
98 if (!parseCtor(classNode)) {
99 return false;
100 }
101 } else if (mReader.name() == QLatin1StringView("enum") || mReader.name() == QLatin1StringView("flag")) {
102 if (!parseEnum(classNode)) {
103 return false;
104 }
105 } else if (mReader.name() == QLatin1StringView("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
119bool XmlParser::parseCtor(ClassNode *classNode)
120{
122 while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1StringView("ctor")))) {
123 mReader.readNext();
124 if (mReader.isStartElement()) {
125 if (mReader.name() == QLatin1StringView("arg")) {
126 const auto attrs = mReader.attributes();
127 const QString name = attrs.value(QLatin1StringView("name")).toString();
128 const QString def = attrs.value(QLatin1StringView("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
141bool XmlParser::parseEnum(ClassNode *classNode)
142{
143 const auto attrs = mReader.attributes();
144 if (!attrs.hasAttribute(QLatin1StringView("name"))) {
145 printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!"));
146 return false;
147 }
148
149 auto enumNode = new EnumNode(attrs.value(QLatin1StringView("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() == QLatin1StringView("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
168bool XmlParser::parseEnumValue(EnumNode *enumNode)
169{
170 Q_ASSERT(mReader.name() == QLatin1StringView("value"));
171
172 const auto attrs = mReader.attributes();
173 if (!attrs.hasAttribute(QLatin1StringView("name"))) {
174 printError(QStringLiteral("Missing \"name\" attribute in <value> tag!"));
175 return false;
176 }
177
178 auto valueNode = new EnumValueNode(attrs.value(QLatin1StringView("name")).toString(), enumNode);
179 if (attrs.hasAttribute(QLatin1StringView("value"))) {
180 valueNode->setValue(attrs.value(QLatin1StringView("value")).toString());
181 }
182
183 return true;
184}
185
186bool XmlParser::parseParam(ClassNode *classNode)
187{
188 Q_ASSERT(mReader.name() == QLatin1StringView("param"));
189
190 const auto attrs = mReader.attributes();
191 if (!attrs.hasAttribute(QLatin1StringView("name"))) {
192 printError(QStringLiteral("Missing \"name\" attribute in <param> tag!"));
193 return false;
194 }
195 if (!attrs.hasAttribute(QLatin1StringView("type"))) {
196 printError(QStringLiteral("Missing \"type\" attribute in <param> tag!"));
197 return false;
198 }
199
200 const auto name = attrs.value(QLatin1StringView("name")).toString();
201 const auto type = attrs.value(QLatin1StringView("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(QLatin1StringView("default"))) {
213 paramNode->setDefaultValue(attrs.value(QLatin1StringView("default")).toString());
214 }
215 if (attrs.hasAttribute(QLatin1StringView("readOnly"))) {
216 paramNode->setReadOnly(attrs.value(QLatin1StringView("readOnly")) == QLatin1StringView("true"));
217 }
218 if (attrs.hasAttribute(QLatin1StringView("asReference"))) {
219 paramNode->setAsReference(attrs.value(QLatin1StringView("asReference")) == QLatin1StringView("true"));
220 }
221
222 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("param"))) {
223 mReader.readNext();
224 if (mReader.isStartElement()) {
225 if (mReader.name() == QLatin1StringView("setter")) {
226 if (!parseSetter(paramNode)) {
227 return false;
228 }
229 } else if (mReader.name() == QLatin1StringView("depends")) {
230 auto dependsAttrs = mReader.attributes();
231 if (!dependsAttrs.hasAttribute(QLatin1StringView("enum"))) {
232 printError(QStringLiteral("Missing \"enum\" attribute in <depends> tag!"));
233 return false;
234 }
235 if (!dependsAttrs.hasAttribute(QLatin1StringView("value"))) {
236 printError(QStringLiteral("Missing \"value\" attribute in <depends> tag!"));
237 return false;
238 }
239 paramNode->addDependency(dependsAttrs.value(QLatin1StringView("enum")).toString(), dependsAttrs.value(QLatin1StringView("value")).toString());
240 } else {
241 printError(QStringLiteral("Unknown tag: ").append(mReader.name()));
242 return false;
243 }
244 }
245 }
246
247 return true;
248}
249
250bool XmlParser::parseSetter(PropertyNode *parent)
251{
252 const auto attrs = mReader.attributes();
253 auto setter = new PropertyNode::Setter;
254 setter->name = attrs.value(QLatin1StringView("name")).toString();
255 setter->type = attrs.value(QLatin1StringView("type")).toString();
256
257 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("setter"))) {
258 mReader.readNext();
259 if (mReader.isStartElement()) {
260 if (mReader.name() == QLatin1StringView("append")) {
261 setter->append = mReader.attributes().value(QLatin1StringView("name")).toString();
262 } else if (mReader.name() == QLatin1StringView("remove")) {
263 setter->remove = mReader.attributes().value(QLatin1StringView("name")).toString();
264 }
265 }
266 }
267
268 parent->setSetter(setter);
269
270 return true;
271}
272
273void XmlParser::printError(const QString &error)
274{
275 std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber() << ": " << qPrintable(error) << std::endl;
276}
char * toString(const EngineQuery &query)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardAction id)
QString toString() const const
QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const const
bool atEnd() const const
QXmlStreamAttributes attributes() const const
qint64 columnNumber() const const
bool isEndElement() const const
bool isStartElement() const const
qint64 lineNumber() const const
QStringView name() const const
TokenType readNext()
void setDevice(QIODevice *device)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:08:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.