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 "qdbusreply.h" |
5 | #include "qdbusmetatype.h" |
6 | #include "qdbusmetatype_p.h" |
7 | #include <QDebug> |
8 | |
9 | #ifndef QT_NO_DBUS |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | using namespace Qt::StringLiterals; |
14 | |
15 | /*! |
16 | \class QDBusReply |
17 | \inmodule QtDBus |
18 | \since 4.2 |
19 | |
20 | \brief The QDBusReply class stores the reply for a method call to a remote object. |
21 | |
22 | A QDBusReply object is a subset of the QDBusMessage object that represents a method call's |
23 | reply. It contains only the first output argument or the error code and is used by |
24 | QDBusInterface-derived classes to allow returning the error code as the function's return |
25 | argument. |
26 | |
27 | It can be used in the following manner: |
28 | \snippet code/src_qdbus_qdbusreply.cpp 0 |
29 | |
30 | If the remote method call cannot fail, you can skip the error checking: |
31 | \snippet code/src_qdbus_qdbusreply.cpp 1 |
32 | |
33 | However, if it does fail under those conditions, the value returned by QDBusReply<T>::value() is |
34 | a default-constructed value. It may be indistinguishable from a valid return value. |
35 | |
36 | QDBusReply objects are used for remote calls that have no output |
37 | arguments or return values (i.e., they have a "void" return |
38 | type). Use the isValid() function to test if the reply succeeded. |
39 | |
40 | \sa QDBusMessage, QDBusInterface |
41 | */ |
42 | |
43 | /*! |
44 | \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusReply &other) |
45 | \since 5.15 |
46 | |
47 | Constructs a copy of \a other. |
48 | */ |
49 | |
50 | /*! |
51 | \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusMessage &reply) |
52 | Automatically construct a QDBusReply object from the reply message \a reply, extracting the |
53 | first return value from it if it is a success reply. |
54 | */ |
55 | |
56 | /*! |
57 | \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusPendingReply<T> &reply) |
58 | Constructs a QDBusReply object from the pending reply message, \a reply. |
59 | */ |
60 | |
61 | /*! |
62 | \fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusPendingCall &pcall) |
63 | Automatically construct a QDBusReply object from the asynchronous |
64 | pending call \a pcall. If the call isn't finished yet, QDBusReply |
65 | will call QDBusPendingCall::waitForFinished(), which is a blocking |
66 | operation. |
67 | |
68 | If the return types patch, QDBusReply will extract the first |
69 | return argument from the reply. |
70 | */ |
71 | |
72 | /*! |
73 | \fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusError &error) |
74 | Constructs an error reply from the D-Bus error code given by \a error. |
75 | */ |
76 | |
77 | /*! |
78 | \fn template <typename T> QDBusReply<T>::operator=(const QDBusReply &other) |
79 | Makes this object be a copy of the object \a other. |
80 | */ |
81 | |
82 | /*! |
83 | \fn template <typename T> QDBusReply<T>::operator=(const QDBusError &dbusError) |
84 | Sets this object to contain the error code given by \a dbusError. You |
85 | can later access it with error(). |
86 | */ |
87 | |
88 | /*! |
89 | \fn template <typename T> QDBusReply<T>::operator=(const QDBusMessage &reply) |
90 | |
91 | Makes this object contain the \a reply message. If \a reply |
92 | is an error message, this function will |
93 | copy the error code and message into this object |
94 | |
95 | If \a reply is a standard reply message and contains at least |
96 | one parameter, it will be copied into this object, as long as it |
97 | is of the correct type. If it's not of the same type as this |
98 | QDBusError object, this function will instead set an error code |
99 | indicating a type mismatch. |
100 | */ |
101 | |
102 | /*! |
103 | \fn template <typename T> QDBusReply<T>::operator=(const QDBusPendingCall &pcall) |
104 | |
105 | Makes this object contain the reply specified by the pending |
106 | asynchronous call \a pcall. If the call is not finished yet, this |
107 | function will call QDBusPendingCall::waitForFinished() to block |
108 | until the reply arrives. |
109 | |
110 | If \a pcall finishes with an error message, this function will |
111 | copy the error code and message into this object |
112 | |
113 | If \a pcall finished with a standard reply message and contains at |
114 | least one parameter, it will be copied into this object, as long |
115 | as it is of the correct type. If it's not of the same type as this |
116 | QDBusError object, this function will instead set an error code |
117 | indicating a type mismatch. |
118 | */ |
119 | |
120 | /*! |
121 | \fn template <typename T> bool QDBusReply<T>::isValid() const |
122 | |
123 | Returns \c true if no error occurred; otherwise, returns \c false. |
124 | |
125 | \sa error() |
126 | */ |
127 | |
128 | /*! |
129 | \fn template<typename T> const QDBusError& QDBusReply<T>::error() const |
130 | |
131 | Returns the error code that was returned from the remote function call. If the remote call did |
132 | not return an error (i.e., if it succeeded), then the QDBusError object that is returned will |
133 | not be a valid error code (QDBusError::isValid() will return false). |
134 | |
135 | \sa isValid() |
136 | */ |
137 | |
138 | /*! |
139 | \fn template <typename T> const QDBusError& QDBusReply<T>::error() |
140 | \overload |
141 | */ |
142 | |
143 | /*! |
144 | \fn template <typename T> QDBusReply<T>::value() const |
145 | Returns the remote function's calls return value. If the remote call returned with an error, |
146 | the return value of this function is undefined and may be undistinguishable from a valid return |
147 | value. |
148 | |
149 | This function is not available if the remote call returns \c void. |
150 | */ |
151 | |
152 | /*! |
153 | \fn template <typename T> QDBusReply<T>::operator Type() const |
154 | Returns the same as value(). |
155 | |
156 | This function is not available if the remote call returns \c void. |
157 | */ |
158 | |
159 | /*! |
160 | \internal |
161 | Fills in the QDBusReply data \a error and \a data from the reply message \a reply. |
162 | */ |
163 | void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data) |
164 | { |
165 | error = QDBusError(reply); |
166 | |
167 | if (error.isValid()) { |
168 | data = QVariant(); // clear it |
169 | return; |
170 | } |
171 | |
172 | if (reply.arguments().size() >= 1 && reply.arguments().at(i: 0).metaType() == data.metaType()) { |
173 | data = reply.arguments().at(i: 0); |
174 | return; |
175 | } |
176 | |
177 | const char *expectedSignature = QDBusMetaType::typeToSignature(type: data.metaType()); |
178 | const char *receivedType = nullptr; |
179 | QByteArray receivedSignature; |
180 | |
181 | if (reply.arguments().size() >= 1) { |
182 | if (reply.arguments().at(i: 0).metaType() == QDBusMetaTypeId::argument()) { |
183 | // compare signatures instead |
184 | QDBusArgument arg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0)); |
185 | receivedSignature = arg.currentSignature().toLatin1(); |
186 | if (receivedSignature == expectedSignature) { |
187 | // matched. Demarshall it |
188 | QDBusMetaType::demarshall(arg, id: data.metaType(), data: data.data()); |
189 | return; |
190 | } |
191 | } else { |
192 | // not an argument and doesn't match? |
193 | QMetaType type = reply.arguments().at(i: 0).metaType(); |
194 | receivedType = type.name(); |
195 | receivedSignature = QDBusMetaType::typeToSignature(type); |
196 | } |
197 | } |
198 | |
199 | // error |
200 | if (receivedSignature.isEmpty()) |
201 | receivedSignature = "<empty signature>" ; |
202 | QString errorMsg; |
203 | if (receivedType) { |
204 | errorMsg = "Unexpected reply signature: got \"%1\" (%4), expected \"%2\" (%3)"_L1 |
205 | .arg(args: QLatin1StringView(receivedSignature), |
206 | args: QLatin1StringView(expectedSignature), |
207 | args: QLatin1StringView(data.typeName()), |
208 | args: QLatin1StringView(receivedType)); |
209 | } else { |
210 | errorMsg = "Unexpected reply signature: got \"%1\", expected \"%2\" (%3)"_L1 |
211 | .arg(args: QLatin1StringView(receivedSignature), |
212 | args: QLatin1StringView(expectedSignature), |
213 | args: QLatin1StringView(data.typeName())); |
214 | } |
215 | |
216 | error = QDBusError(QDBusError::InvalidSignature, errorMsg); |
217 | data = QVariant(); // clear it |
218 | } |
219 | |
220 | QT_END_NAMESPACE |
221 | |
222 | #endif // QT_NO_DBUS |
223 | |