File indexing completed on 2024-11-10 04:40:47
0001 /* 0002 SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "xmlparser.h" 0008 #include "nodetree.h" 0009 0010 #include <QFile> 0011 0012 #include <iostream> 0013 0014 #define qPrintableRef(x) reinterpret_cast<const char *>((x).unicode()) 0015 0016 XmlParser::XmlParser() 0017 { 0018 } 0019 0020 XmlParser::~XmlParser() 0021 { 0022 } 0023 0024 Node const *XmlParser::tree() const 0025 { 0026 return mTree.get(); 0027 } 0028 0029 bool XmlParser::parse(const QString &filename) 0030 { 0031 QFile file(filename); 0032 if (!file.open(QIODevice::ReadOnly)) { 0033 std::cerr << qPrintable(file.errorString()); 0034 return false; 0035 } 0036 0037 mReader.setDevice(&file); 0038 while (!mReader.atEnd()) { 0039 mReader.readNext(); 0040 if (mReader.isStartElement() && mReader.name() == QLatin1StringView("protocol")) { 0041 if (!parseProtocol()) { 0042 return false; 0043 } 0044 } 0045 } 0046 0047 return true; 0048 } 0049 0050 bool XmlParser::parseProtocol() 0051 { 0052 Q_ASSERT(mReader.name() == QLatin1StringView("protocol")); 0053 0054 const auto attrs = mReader.attributes(); 0055 if (!attrs.hasAttribute(QLatin1StringView("version"))) { 0056 printError(QStringLiteral("Missing \"version\" attribute in <protocol> tag!")); 0057 return false; 0058 } 0059 0060 auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1StringView("version")).toInt()); 0061 0062 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("protocol"))) { 0063 mReader.readNext(); 0064 if (mReader.isStartElement()) { 0065 const auto elemName = mReader.name(); 0066 if (elemName == QLatin1StringView("class") || elemName == QLatin1StringView("command") || elemName == QLatin1StringView("response") 0067 || elemName == QLatin1StringView("notification")) { 0068 if (!parseCommand(documentNode.get())) { 0069 return false; 0070 } 0071 } else { 0072 printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); 0073 return false; 0074 } 0075 } 0076 } 0077 0078 mTree = std::move(documentNode); 0079 0080 return true; 0081 } 0082 0083 bool XmlParser::parseCommand(DocumentNode *documentNode) 0084 { 0085 const auto attrs = mReader.attributes(); 0086 if (!attrs.hasAttribute(QLatin1StringView("name"))) { 0087 printError(QStringLiteral("Missing \"name\" attribute in command tag!")); 0088 return false; 0089 } 0090 0091 auto classNode = new ClassNode(attrs.value(QLatin1StringView("name")).toString(), ClassNode::elementNameToType(mReader.name()), documentNode); 0092 new CtorNode({}, classNode); 0093 0094 while (!mReader.atEnd() && !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) { 0095 mReader.readNext(); 0096 if (mReader.isStartElement()) { 0097 if (mReader.name() == QLatin1StringView("ctor")) { 0098 if (!parseCtor(classNode)) { 0099 return false; 0100 } 0101 } else if (mReader.name() == QLatin1StringView("enum") || mReader.name() == QLatin1StringView("flag")) { 0102 if (!parseEnum(classNode)) { 0103 return false; 0104 } 0105 } else if (mReader.name() == QLatin1StringView("param")) { 0106 if (!parseParam(classNode)) { 0107 return false; 0108 } 0109 } else { 0110 printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); 0111 return false; 0112 } 0113 } 0114 } 0115 0116 return true; 0117 } 0118 0119 bool XmlParser::parseCtor(ClassNode *classNode) 0120 { 0121 QList<CtorNode::Argument> args; 0122 while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1StringView("ctor")))) { 0123 mReader.readNext(); 0124 if (mReader.isStartElement()) { 0125 if (mReader.name() == QLatin1StringView("arg")) { 0126 const auto attrs = mReader.attributes(); 0127 const QString name = attrs.value(QLatin1StringView("name")).toString(); 0128 const QString def = attrs.value(QLatin1StringView("default")).toString(); 0129 args << CtorNode::Argument{name, QString(), def}; 0130 } else { 0131 printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); 0132 return false; 0133 } 0134 } 0135 } 0136 new CtorNode(args, classNode); 0137 0138 return true; 0139 } 0140 0141 bool XmlParser::parseEnum(ClassNode *classNode) 0142 { 0143 const auto attrs = mReader.attributes(); 0144 if (!attrs.hasAttribute(QLatin1StringView("name"))) { 0145 printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!")); 0146 return false; 0147 } 0148 0149 auto enumNode = new EnumNode(attrs.value(QLatin1StringView("name")).toString(), EnumNode::elementNameToType(mReader.name()), classNode); 0150 0151 while (!mReader.atEnd() && !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) { 0152 mReader.readNext(); 0153 if (mReader.isStartElement()) { 0154 if (mReader.name() == QLatin1StringView("value")) { 0155 if (!parseEnumValue(enumNode)) { 0156 return false; 0157 } 0158 } else { 0159 printError(QStringLiteral("Invalid tag inside of enum/flag tag: ").append(mReader.name())); 0160 return false; 0161 } 0162 } 0163 } 0164 0165 return true; 0166 } 0167 0168 bool XmlParser::parseEnumValue(EnumNode *enumNode) 0169 { 0170 Q_ASSERT(mReader.name() == QLatin1StringView("value")); 0171 0172 const auto attrs = mReader.attributes(); 0173 if (!attrs.hasAttribute(QLatin1StringView("name"))) { 0174 printError(QStringLiteral("Missing \"name\" attribute in <value> tag!")); 0175 return false; 0176 } 0177 0178 auto valueNode = new EnumValueNode(attrs.value(QLatin1StringView("name")).toString(), enumNode); 0179 if (attrs.hasAttribute(QLatin1StringView("value"))) { 0180 valueNode->setValue(attrs.value(QLatin1StringView("value")).toString()); 0181 } 0182 0183 return true; 0184 } 0185 0186 bool XmlParser::parseParam(ClassNode *classNode) 0187 { 0188 Q_ASSERT(mReader.name() == QLatin1StringView("param")); 0189 0190 const auto attrs = mReader.attributes(); 0191 if (!attrs.hasAttribute(QLatin1StringView("name"))) { 0192 printError(QStringLiteral("Missing \"name\" attribute in <param> tag!")); 0193 return false; 0194 } 0195 if (!attrs.hasAttribute(QLatin1StringView("type"))) { 0196 printError(QStringLiteral("Missing \"type\" attribute in <param> tag!")); 0197 return false; 0198 } 0199 0200 const auto name = attrs.value(QLatin1StringView("name")).toString(); 0201 const auto type = attrs.value(QLatin1StringView("type")).toString(); 0202 0203 for (const auto child : classNode->children()) { 0204 if (child->type() == Node::Ctor) { 0205 auto ctor = const_cast<CtorNode *>(static_cast<const CtorNode *>(child)); 0206 ctor->setArgumentType(name, type); 0207 } 0208 } 0209 0210 auto paramNode = new PropertyNode(name, type, classNode); 0211 0212 if (attrs.hasAttribute(QLatin1StringView("default"))) { 0213 paramNode->setDefaultValue(attrs.value(QLatin1StringView("default")).toString()); 0214 } 0215 if (attrs.hasAttribute(QLatin1StringView("readOnly"))) { 0216 paramNode->setReadOnly(attrs.value(QLatin1StringView("readOnly")) == QLatin1StringView("true")); 0217 } 0218 if (attrs.hasAttribute(QLatin1StringView("asReference"))) { 0219 paramNode->setAsReference(attrs.value(QLatin1StringView("asReference")) == QLatin1StringView("true")); 0220 } 0221 0222 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("param"))) { 0223 mReader.readNext(); 0224 if (mReader.isStartElement()) { 0225 if (mReader.name() == QLatin1StringView("setter")) { 0226 if (!parseSetter(paramNode)) { 0227 return false; 0228 } 0229 } else if (mReader.name() == QLatin1StringView("depends")) { 0230 auto dependsAttrs = mReader.attributes(); 0231 if (!dependsAttrs.hasAttribute(QLatin1StringView("enum"))) { 0232 printError(QStringLiteral("Missing \"enum\" attribute in <depends> tag!")); 0233 return false; 0234 } 0235 if (!dependsAttrs.hasAttribute(QLatin1StringView("value"))) { 0236 printError(QStringLiteral("Missing \"value\" attribute in <depends> tag!")); 0237 return false; 0238 } 0239 paramNode->addDependency(dependsAttrs.value(QLatin1StringView("enum")).toString(), dependsAttrs.value(QLatin1StringView("value")).toString()); 0240 } else { 0241 printError(QStringLiteral("Unknown tag: ").append(mReader.name())); 0242 return false; 0243 } 0244 } 0245 } 0246 0247 return true; 0248 } 0249 0250 bool XmlParser::parseSetter(PropertyNode *parent) 0251 { 0252 const auto attrs = mReader.attributes(); 0253 auto setter = new PropertyNode::Setter; 0254 setter->name = attrs.value(QLatin1StringView("name")).toString(); 0255 setter->type = attrs.value(QLatin1StringView("type")).toString(); 0256 0257 while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView("setter"))) { 0258 mReader.readNext(); 0259 if (mReader.isStartElement()) { 0260 if (mReader.name() == QLatin1StringView("append")) { 0261 setter->append = mReader.attributes().value(QLatin1StringView("name")).toString(); 0262 } else if (mReader.name() == QLatin1StringView("remove")) { 0263 setter->remove = mReader.attributes().value(QLatin1StringView("name")).toString(); 0264 } 0265 } 0266 } 0267 0268 parent->setSetter(setter); 0269 0270 return true; 0271 } 0272 0273 void XmlParser::printError(const QString &error) 0274 { 0275 std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber() << ": " << qPrintable(error) << std::endl; 0276 }