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{
121 QList<CtorNode::Argument> args;
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)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.