summaryrefslogtreecommitdiffstats
path: root/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp')
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp198
1 files changed, 125 insertions, 73 deletions
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
index 23e4514edf..3b7d73894b 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qbuffer.h>
#include <qbytearray.h>
@@ -40,6 +15,9 @@
#include <qdbusconnection.h> // for the Export* flags
#include <private/qdbusconnection_p.h> // for the qDBusCheckAsyncTag
+#include <private/qdbusmetatype_p.h> // for QDBusMetaTypeId::init()
+
+using namespace Qt::StringLiterals;
// copied from dbus-protocol.h:
static const char docTypeHeader[] =
@@ -60,7 +38,7 @@ static const char docTypeHeader[] =
#define PROGRAMNAME "qdbuscpp2xml"
#define PROGRAMVERSION "0.2"
-#define PROGRAMCOPYRIGHT "Copyright (C) 2021 The Qt Company Ltd."
+#define PROGRAMCOPYRIGHT QT_COPYRIGHT
static QString outputFile;
static int flags;
@@ -71,13 +49,14 @@ static const char help[] =
"produces the D-Bus Introspection XML."
"\n"
"Options:\n"
- " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
- " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
- " -a Output all scriptable contents (equivalent to -psm)\n"
- " -A Output all contents (equivalent to -PSM)\n"
- " -o <filename> Write the output to file <filename>\n"
- " -h Show this information\n"
- " -V Show the program version and quit.\n"
+ " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n"
+ " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n"
+ " -a Output all scriptable contents (equivalent to -psm)\n"
+ " -A Output all contents (equivalent to -PSM)\n"
+ " -t <type>=<dbustype> Output <type> (ex: MyStruct) as <dbustype> (ex: {ss})\n"
+ " -o <filename> Write the output to file <filename>\n"
+ " -h Show this information\n"
+ " -V Show the program version and quit.\n"
"\n";
int qDBusParametersForMethod(const FunctionDef &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
@@ -94,7 +73,7 @@ int qDBusParametersForMethod(const FunctionDef &mm, QList<QMetaType> &metaTypes,
static inline QString typeNameToXml(const char *typeName)
{
- QString plain = QLatin1String(typeName);
+ QString plain = QLatin1StringView(typeName);
return plain.toHtmlEscaped();
}
@@ -120,7 +99,8 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
return QString();
}
} else if (!mm.normalizedType.isEmpty()) {
- return QString(); // wasn't a valid type
+ qWarning() << "Unregistered return type:" << mm.normalizedType.constData();
+ return QString();
}
}
QList<ArgumentDef> names = mm.arguments;
@@ -131,13 +111,13 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
qWarning() << qPrintable(errorMsg);
return QString(); // invalid form
}
- if (isSignal && inputCount + 1 != types.count())
+ if (isSignal && inputCount + 1 != types.size())
return QString(); // signal with output arguments?
if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message())
return QString(); // signal with QDBusMessage argument?
bool isScriptable = mm.isScriptable;
- for (int j = 1; j < types.count(); ++j) {
+ for (qsizetype j = 1; j < types.size(); ++j) {
// input parameter for a slot or output for a signal
if (types.at(j) == QDBusMetaTypeId::message()) {
isScriptable = true;
@@ -153,14 +133,14 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
const char *signature = QDBusMetaType::typeToSignature(QMetaType(types.at(j)));
xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
.arg(name,
- QLatin1String(signature),
- isOutput ? QLatin1String("out") : QLatin1String("in"));
+ QLatin1StringView(signature),
+ isOutput ? "out"_L1 : "in"_L1);
// do we need to describe this argument?
if (!QDBusMetaType::signatureToMetaType(signature).isValid()) {
const char *typeName = QMetaType(types.at(j)).name();
xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
- .arg(isOutput ? QLatin1String("Out") : QLatin1String("In"))
+ .arg(isOutput ? "Out"_L1 : "In"_L1)
.arg(isOutput && !isSignal ? j - inputCount : j - 1)
.arg(typeNameToXml(typeName));
}
@@ -178,12 +158,10 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
if (qDBusCheckAsyncTag(mm.tag.constData()))
// add the no-reply annotation
- xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
- " value=\"true\"/>\n");
+ xml += " <annotation name=\"" ANNOTATION_NO_WAIT "\" value=\"true\"/>\n"_L1;
QString retval = xml;
- retval += QString::fromLatin1(" </%1>\n")
- .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+ retval += QString::fromLatin1(" </%1>\n").arg(isSignal ? "signal"_L1 : "method"_L1);
return retval;
}
@@ -207,6 +185,8 @@ static QString generateInterfaceXml(const ClassDef *mo)
access |= 1;
if (!mp.write.isEmpty())
access |= 2;
+ if (!mp.member.isEmpty())
+ access |= 3;
int typeId = QMetaType::fromName(mp.type).id();
if (!typeId) {
@@ -219,15 +199,15 @@ static QString generateInterfaceXml(const ClassDef *mo)
continue;
retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
- .arg(QLatin1String(mp.name),
- QLatin1String(signature),
- QLatin1String(accessvalues[access]));
+ .arg(QLatin1StringView(mp.name),
+ QLatin1StringView(signature),
+ QLatin1StringView(accessvalues[access]));
if (!QDBusMetaType::signatureToMetaType(signature).isValid()) {
retval += QString::fromLatin1(">\n <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
.arg(typeNameToXml(mp.type.constData()));
} else {
- retval += QLatin1String("/>\n");
+ retval += "/>\n"_L1;
}
}
}
@@ -270,17 +250,17 @@ QString qDBusInterfaceFromClassDef(const ClassDef *mo)
if (cid.name == QCLASSINFO_DBUS_INTERFACE)
return QString::fromUtf8(cid.value);
}
- interface = QLatin1String(mo->classname);
- interface.replace(QLatin1String("::"), QLatin1String("."));
+ interface = QLatin1StringView(mo->classname);
+ interface.replace("::"_L1, "."_L1);
- if (interface.startsWith(QLatin1String("QDBus"))) {
- interface.prepend(QLatin1String("org.qtproject.QtDBus."));
- } else if (interface.startsWith(QLatin1Char('Q')) &&
- interface.length() >= 2 && interface.at(1).isUpper()) {
+ if (interface.startsWith("QDBus"_L1)) {
+ interface.prepend("org.qtproject.QtDBus."_L1);
+ } else if (interface.startsWith(u'Q') &&
+ interface.size() >= 2 && interface.at(1).isUpper()) {
// assume it's Qt
- interface.prepend(QLatin1String("local.org.qtproject.Qt."));
+ interface.prepend("local.org.qtproject.Qt."_L1);
} else {
- interface.prepend(QLatin1String("local."));
+ interface.prepend("local."_L1);
}
return interface;
@@ -318,19 +298,54 @@ static void showVersion()
exit(0);
}
+class CustomType {
+public:
+ CustomType(const QByteArray &typeName)
+ : typeName(typeName)
+ {
+ metaTypeImpl.name = typeName.constData();
+ }
+ QMetaType metaType() const { return QMetaType(&metaTypeImpl); }
+
+private:
+ // not copiable and not movable because of QBasicAtomicInt
+ QtPrivate::QMetaTypeInterface metaTypeImpl =
+ { /*.revision=*/ 0,
+ /*.alignment=*/ 0,
+ /*.size=*/ 0,
+ /*.flags=*/ 0,
+ /*.typeId=*/ 0,
+ /*.metaObjectFn=*/ 0,
+ /*.name=*/ nullptr, // set by the constructor
+ /*.defaultCtr=*/ nullptr,
+ /*.copyCtr=*/ nullptr,
+ /*.moveCtr=*/ nullptr,
+ /*.dtor=*/ nullptr,
+ /*.equals=*/ nullptr,
+ /*.lessThan=*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ };
+ QByteArray typeName;
+};
+// Unlike std::vector, std::deque works with non-copiable non-movable types
+static std::deque<CustomType> s_customTypes;
+
static void parseCmdLine(QStringList &arguments)
{
flags = 0;
- for (int i = 0; i < arguments.count(); ++i) {
+ for (qsizetype i = 0; i < arguments.size(); ++i) {
const QString arg = arguments.at(i);
- if (arg == QLatin1String("--help"))
+ if (arg == "--help"_L1)
showHelp();
- if (!arg.startsWith(QLatin1Char('-')))
+ if (!arg.startsWith(u'-'))
continue;
- char c = arg.count() == 2 ? arg.at(1).toLatin1() : char(0);
+ char c = arg.size() == 2 ? arg.at(1).toLatin1() : char(0);
switch (c) {
case 'P':
flags |= QDBusConnection::ExportNonScriptableProperties;
@@ -360,8 +375,29 @@ static void parseCmdLine(QStringList &arguments)
flags |= QDBusConnection::ExportScriptableContents;
break;
+ case 't':
+ if (arguments.size() < i + 2) {
+ printf("-t expects a type=dbustype argument\n");
+ exit(1);
+ } else {
+ const QByteArray arg = arguments.takeAt(i + 1).toUtf8();
+ // lastIndexOf because the C++ type could contain '=' while the DBus type can't
+ const qsizetype separator = arg.lastIndexOf('=');
+ if (separator == -1) {
+ printf("-t expects a type=dbustype argument, but no '=' was found\n");
+ exit(1);
+ }
+ const QByteArray type = arg.left(separator);
+ const QByteArray dbustype = arg.mid(separator+1);
+
+ s_customTypes.emplace_back(type);
+ QMetaType metaType = s_customTypes.back().metaType();
+ QDBusMetaType::registerCustomType(metaType, dbustype);
+ }
+ break;
+
case 'o':
- if (arguments.count() < i + 2 || arguments.at(i + 1).startsWith(QLatin1Char('-'))) {
+ if (arguments.size() < i + 2 || arguments.at(i + 1).startsWith(u'-')) {
printf("-o expects a filename\n");
exit(1);
}
@@ -396,18 +432,30 @@ int main(int argc, char **argv)
args.append(QString::fromLocal8Bit(argv[n]));
parseCmdLine(args);
- QList<ClassDef> classes;
+ QDBusMetaTypeId::init();
- for (int i = 0; i < args.count(); ++i) {
- const QString arg = args.at(i);
+ QList<ClassDef> classes;
- if (arg.startsWith(QLatin1Char('-')))
+ if (args.isEmpty())
+ args << u"-"_s;
+ for (const auto &arg: std::as_const(args)) {
+ if (arg.startsWith(u'-') && arg.size() > 1)
continue;
- QFile f(arg);
- if (!f.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ QFile f;
+ bool fileIsOpen;
+ QString fileName;
+ if (arg == u'-') {
+ fileName = "stdin"_L1;
+ fileIsOpen = f.open(stdin, QIODevice::ReadOnly | QIODevice::Text);
+ } else {
+ fileName = arg;
+ f.setFileName(arg);
+ fileIsOpen = f.open(QIODevice::ReadOnly | QIODevice::Text);
+ }
+ if (!fileIsOpen) {
fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
- qPrintable(arg), qPrintable(f.errorString()));
+ qPrintable(fileName), qPrintable(f.errorString()));
return 1;
}
@@ -433,11 +481,15 @@ int main(int argc, char **argv)
QFile output;
if (outputFile.isEmpty()) {
- output.open(stdout, QIODevice::WriteOnly);
+ if (!output.open(stdout, QIODevice::WriteOnly)) {
+ fprintf(stderr, PROGRAMNAME ": could not open standard output: %s\n",
+ qPrintable(output.errorString()));
+ return 1;
+ }
} else {
output.setFileName(outputFile);
if (!output.open(QIODevice::WriteOnly)) {
- fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
+ fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s\n",
qPrintable(outputFile), qPrintable(output.errorString()));
return 1;
}
@@ -445,7 +497,7 @@ int main(int argc, char **argv)
output.write(docTypeHeader);
output.write("<node>\n");
- for (const ClassDef &cdef : qAsConst(classes)) {
+ for (const ClassDef &cdef : std::as_const(classes)) {
QString xml = qDBusGenerateClassDefXml(&cdef);
output.write(std::move(xml).toLocal8Bit());
}