1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <string.h>
5
6#ifndef QT_BOOTSTRAPPED
7#include <QtCore/qcoreapplication.h>
8#include <QtCore/qlist.h>
9#include <QtCore/qmetaobject.h>
10#include <QtCore/qvariant.h>
11#include <private/qurl_p.h>
12
13#include "qdbusutil_p.h"
14#include "qdbusconnection_p.h"
15#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
16#endif
17#include "qdbusmetatype_p.h"
18
19#ifndef QT_NO_DBUS
20
21QT_BEGIN_NAMESPACE
22
23using namespace Qt::StringLiterals;
24
25bool qDBusCheckAsyncTag(const char *tag)
26{
27 static const char noReplyTag[] = "Q_NOREPLY";
28 if (!tag || !*tag)
29 return false;
30
31 const char *p = strstr(haystack: tag, needle: noReplyTag);
32 if (p != nullptr &&
33 (p == tag || *(p-1) == ' ') &&
34 (p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' '))
35 return true;
36
37 return false;
38}
39
40#ifndef QT_BOOTSTRAPPED
41
42QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
43{
44 QString interface;
45
46 int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
47 if (idx >= mo->classInfoOffset()) {
48 interface = QLatin1StringView(mo->classInfo(index: idx).value());
49 } else {
50 interface = QLatin1StringView(mo->className());
51 interface.replace(before: "::"_L1, after: "."_L1);
52
53 if (interface.startsWith(s: "QDBus"_L1)) {
54 interface.prepend(s: "org.qtproject.QtDBus."_L1);
55 } else if (interface.startsWith(c: u'Q') &&
56 interface.size() >= 2 && interface.at(i: 1).isUpper()) {
57 // assume it's Qt
58 interface.prepend(s: "org.qtproject.Qt."_L1);
59 } else if (!QCoreApplication::instance()||
60 QCoreApplication::instance()->applicationName().isEmpty()) {
61 interface.prepend(s: "local."_L1);
62 } else {
63 QString domainName = QCoreApplication::instance()->applicationName();
64 const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
65 if (organizationDomain.isEmpty())
66 domainName.append(s: ".local"_L1);
67 else
68 domainName.append(c: u'.').append(s: organizationDomain);
69
70 // Domain names used to produce interface names should be IDN-encoded.
71 QString encodedDomainName = qt_ACE_do(domain: domainName, op: ToAceOnly, dot: ForbidLeadingDot);
72 if (encodedDomainName.isEmpty()) {
73 interface.prepend(s: "local."_L1);
74 return interface;
75 }
76
77 // Hyphens are not allowed in interface names and should be replaced
78 // by underscores.
79 encodedDomainName.replace(before: u'-', after: u'_');
80
81 auto nameParts = QStringView{ encodedDomainName }.split(sep: u'.', behavior: Qt::SkipEmptyParts);
82
83 QString composedDomain;
84 // + 1 for additional dot, e.g. domainName equals "App.example.com",
85 // then composedDomain will be equal "com.example.App."
86 composedDomain.reserve(asize: encodedDomainName.size() + nameParts.size() + 1);
87 for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) {
88 // An interface name cannot start with a digit, and cannot
89 // contain digits immediately following a period. Prefix such
90 // digits with underscores.
91 if (it->first().isDigit())
92 composedDomain += u'_';
93 composedDomain += *it + u'.';
94 }
95
96 interface.prepend(s: composedDomain);
97 }
98 }
99
100 return interface;
101}
102
103bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
104{
105 const QMetaObject *mo = obj->metaObject();
106 for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
107 if (interface_name == qDBusInterfaceFromMetaObject(mo))
108 return true;
109 return false;
110}
111
112// calculates the metatypes for the method
113// the slot must have the parameters in the following form:
114// - zero or more value or const-ref parameters of any kind
115// - zero or one const ref of QDBusMessage
116// - zero or more non-const ref parameters
117// No parameter may be a template.
118// this function returns -1 if the parameters don't match the above form
119// this function returns the number of *input* parameters, including the QDBusMessage one if any
120// this function does not check the return type, so metaTypes[0] is always 0 and always present
121// metaTypes.count() >= retval + 1 in all cases
122//
123// sig must be the normalised signature for the method
124int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
125{
126 QList<QByteArray> parameterTypes;
127 parameterTypes.reserve(asize: mm.parameterCount());
128
129 // Not using QMetaMethod::parameterTypes() since we call QMetaType::fromName below
130 // where we need any typedefs resolved already.
131 for (int i = 0; i < mm.parameterCount(); ++i) {
132 QByteArray typeName = mm.parameterMetaType(index: i).name();
133 if (typeName.isEmpty())
134 typeName = mm.parameterTypeName(index: i);
135 parameterTypes.append(t: typeName);
136 }
137
138 return qDBusParametersForMethod(parameters: parameterTypes, metaTypes, errorMsg);
139}
140
141#endif // QT_BOOTSTRAPPED
142
143int qDBusParametersForMethod(const QList<QByteArray> &parameterTypes, QList<QMetaType> &metaTypes,
144 QString &errorMsg)
145{
146 QDBusMetaTypeId::init();
147 metaTypes.clear();
148
149 metaTypes.append(t: QMetaType()); // return type
150 int inputCount = 0;
151 bool seenMessage = false;
152 for (QByteArray type : parameterTypes) {
153 if (type.endsWith(c: '*')) {
154 errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type);
155 return -1;
156 }
157
158 if (type.endsWith(c: '&')) {
159 QByteArray basictype = type;
160 basictype.truncate(pos: type.size() - 1);
161
162 QMetaType id = QMetaType::fromName(name: basictype);
163 if (!id.isValid()) {
164 errorMsg = "Unregistered output type in parameter list: "_L1 + QLatin1StringView(type);
165 return -1;
166 } else if (QDBusMetaType::typeToSignature(type: id) == nullptr)
167 return -1;
168
169 metaTypes.append(t: id);
170 seenMessage = true; // it cannot appear anymore anyways
171 continue;
172 }
173
174 if (seenMessage) { // && !type.endsWith('&')
175 errorMsg = "Invalid method, non-output parameters after message or after output parameters: "_L1 + QLatin1StringView(type);
176 return -1; // not allowed
177 }
178
179 if (type.startsWith(bv: "QVector<"))
180 type = "QList<" + type.mid(index: sizeof("QVector<") - 1);
181
182 QMetaType id = QMetaType::fromName(name: type);
183#ifdef QT_BOOTSTRAPPED
184 // in bootstrap mode QDBusMessage isn't included, thus we need to resolve it manually here
185 if (type == "QDBusMessage") {
186 id = QDBusMetaTypeId::message();
187 }
188#endif
189
190 if (!id.isValid()) {
191 errorMsg = "Unregistered input type in parameter list: "_L1 + QLatin1StringView(type);
192 return -1;
193 }
194
195 if (id == QDBusMetaTypeId::message())
196 seenMessage = true;
197 else if (QDBusMetaType::typeToSignature(type: id) == nullptr) {
198 errorMsg = "Type not registered with QtDBus in parameter list: "_L1 + QLatin1StringView(type);
199 return -1;
200 }
201
202 metaTypes.append(t: id);
203 ++inputCount;
204 }
205
206 return inputCount;
207}
208
209QT_END_NAMESPACE
210
211#endif // QT_NO_DBUS
212

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/dbus/qdbusmisc.cpp