Coverage Report

Created: 2026-01-25 07:18

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