14#define qPrintableRef(x) reinterpret_cast<const char *>((x).unicode()) 
   20XmlParser::~XmlParser()
 
   24Node const *XmlParser::tree()
 const 
   29bool XmlParser::parse(
const QString &filename)
 
   33        std::cerr << qPrintable(file.errorString());
 
   37    mReader.setDevice(&file);
 
   38    while (!mReader.atEnd()) {
 
   40        if (mReader.isStartElement() && mReader.name() == QLatin1StringView(
"protocol")) {
 
   41            if (!parseProtocol()) {
 
   50bool XmlParser::parseProtocol()
 
   52    Q_ASSERT(mReader.name() == QLatin1StringView(
"protocol"));
 
   54    const auto attrs = mReader.attributes();
 
   55    if (!attrs.hasAttribute(QLatin1StringView(
"version"))) {
 
   56        printError(QStringLiteral(
"Missing \"version\" attribute in <protocol> tag!"));
 
   60    auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1StringView(
"version")).toInt());
 
   62    while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"protocol"))) {
 
   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())) {
 
   72                printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
 
   78    mTree = std::move(documentNode);
 
   83bool XmlParser::parseCommand(DocumentNode *documentNode)
 
   85    const auto attrs = mReader.attributes();
 
   86    if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
 
   87        printError(QStringLiteral(
"Missing \"name\" attribute  in command tag!"));
 
   91    auto classNode = 
new ClassNode(attrs.value(QLatin1StringView(
"name")).
toString(), ClassNode::elementNameToType(mReader.name()), documentNode);
 
   92    new CtorNode({}, classNode);
 
   94    while (!mReader.atEnd() && !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) {
 
   96        if (mReader.isStartElement()) {
 
   97            if (mReader.name() == QLatin1StringView(
"ctor")) {
 
   98                if (!parseCtor(classNode)) {
 
  101            } 
else if (mReader.name() == QLatin1StringView(
"enum") || mReader.name() == QLatin1StringView(
"flag")) {
 
  102                if (!parseEnum(classNode)) {
 
  105            } 
else if (mReader.name() == QLatin1StringView(
"param")) {
 
  106                if (!parseParam(classNode)) {
 
  110                printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
 
  119bool XmlParser::parseCtor(ClassNode *classNode)
 
  121    QList<CtorNode::Argument> args;
 
  122    while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1StringView(
"ctor")))) {
 
  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};
 
  131                printError(QStringLiteral(
"Unsupported tag: ").append(mReader.name()));
 
  136    new CtorNode(args, classNode);
 
  141bool XmlParser::parseEnum(ClassNode *classNode)
 
  143    const auto attrs = mReader.attributes();
 
  144    if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
 
  145        printError(QStringLiteral(
"Missing \"name\" attribute in enum/flag tag!"));
 
  149    auto enumNode = 
new EnumNode(attrs.value(QLatin1StringView(
"name")).
toString(), EnumNode::elementNameToType(mReader.name()), classNode);
 
  151    while (!mReader.atEnd() && !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) {
 
  153        if (mReader.isStartElement()) {
 
  154            if (mReader.name() == QLatin1StringView(
"value")) {
 
  155                if (!parseEnumValue(enumNode)) {
 
  159                printError(QStringLiteral(
"Invalid tag inside of enum/flag tag: ").append(mReader.name()));
 
  168bool XmlParser::parseEnumValue(EnumNode *enumNode)
 
  170    Q_ASSERT(mReader.name() == QLatin1StringView(
"value"));
 
  172    const auto attrs = mReader.attributes();
 
  173    if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
 
  174        printError(QStringLiteral(
"Missing \"name\" attribute in <value> tag!"));
 
  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());
 
  186bool XmlParser::parseParam(ClassNode *classNode)
 
  188    Q_ASSERT(mReader.name() == QLatin1StringView(
"param"));
 
  190    const auto attrs = mReader.attributes();
 
  191    if (!attrs.hasAttribute(QLatin1StringView(
"name"))) {
 
  192        printError(QStringLiteral(
"Missing \"name\" attribute in <param> tag!"));
 
  195    if (!attrs.hasAttribute(QLatin1StringView(
"type"))) {
 
  196        printError(QStringLiteral(
"Missing \"type\" attribute in <param> tag!"));
 
  200    const auto name = attrs.value(QLatin1StringView(
"name")).toString();
 
  201    const auto type = attrs.value(QLatin1StringView(
"type")).toString();
 
  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);
 
  210    auto paramNode = 
new PropertyNode(name, type, classNode);
 
  212    if (attrs.hasAttribute(QLatin1StringView(
"default"))) {
 
  213        paramNode->setDefaultValue(attrs.value(QLatin1StringView(
"default")).
toString());
 
  215    if (attrs.hasAttribute(QLatin1StringView(
"readOnly"))) {
 
  216        paramNode->setReadOnly(attrs.value(QLatin1StringView(
"readOnly")) == QLatin1StringView(
"true"));
 
  218    if (attrs.hasAttribute(QLatin1StringView(
"asReference"))) {
 
  219        paramNode->setAsReference(attrs.value(QLatin1StringView(
"asReference")) == QLatin1StringView(
"true"));
 
  222    while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"param"))) {
 
  224        if (mReader.isStartElement()) {
 
  225            if (mReader.name() == QLatin1StringView(
"setter")) {
 
  226                if (!parseSetter(paramNode)) {
 
  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!"));
 
  235                if (!dependsAttrs.hasAttribute(QLatin1StringView(
"value"))) {
 
  236                    printError(QStringLiteral(
"Missing \"value\" attribute in <depends> tag!"));
 
  239                paramNode->addDependency(dependsAttrs.value(QLatin1StringView(
"enum")).
toString(), dependsAttrs.value(QLatin1StringView(
"value")).
toString());
 
  241                printError(QStringLiteral(
"Unknown tag: ").append(mReader.name()));
 
  250bool XmlParser::parseSetter(PropertyNode *parent)
 
  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();
 
  257    while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1StringView(
"setter"))) {
 
  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();
 
  268    parent->setSetter(setter);
 
  273void XmlParser::printError(
const QString &error)
 
  275    std::cerr << 
"Error:" << mReader.lineNumber() << 
":" << mReader.columnNumber() << 
": " << qPrintable(error) << std::endl;
 
char * toString(const EngineQuery &query)
 
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
 
QString name(StandardAction id)