1// Copyright (C) 2017 Ford Motor Company
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 "qremoteobjectdynamicreplica.h"
6#include "qremoteobjectreplica_p.h"
7
8#include <QtCore/qmetaobject.h>
9
10QT_BEGIN_NAMESPACE
11
12/*!
13 \class QRemoteObjectDynamicReplica
14 \inmodule QtRemoteObjects
15 \brief A dynamically instantiated \l {Replica}.
16
17 There are generated replicas (replicas having the header files produced by
18 the \l {repc} {Replica Compiler}), and dynamic replicas, that are generated
19 on-the-fly. This is the class for the dynamic type of replica.
20
21 When the connection to the \l {Source} object is made, the initialization
22 step passes the current property values (see \l {Replica Initialization}).
23 In a DynamicReplica, the property/signal/slot details are also sent,
24 allowing the replica object to be created on-the-fly. This can be convenient
25 in QML or scripting, but has two primary disadvantages. First, the object is
26 in effect "empty" until it is successfully initialized by the \l {Source}.
27 Second, in C++, calls must be made using QMetaObject::invokeMethod(), as the
28 moc generated lookup will not be available.
29
30 This class does not have a public constructor. It can only be instantiated
31 by using the dynamic QRemoteObjectNode::acquire method.
32*/
33
34QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica()
35 : QRemoteObjectReplica()
36{
37}
38
39QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name)
40 : QRemoteObjectReplica(ConstructWithNode)
41{
42 initializeNode(node, name);
43}
44
45/*!
46 Destroys the dynamic replica.
47
48 \sa {Replica Ownership}
49*/
50QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica()
51{
52}
53
54/*!
55 \internal
56 Returns a pointer to the dynamically generated meta-object of this object, or
57 QRemoteObjectDynamicReplica's metaObject if the object is not initialized. This
58 function overrides the QObject::metaObject() virtual function to provide the same
59 functionality for dynamic replicas.
60
61 \sa QObject::metaObject(), {Replica Initialization}
62*/
63const QMetaObject* QRemoteObjectDynamicReplica::metaObject() const
64{
65 auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(src: d_impl);
66 // Returning nullptr will likely result in a crash if this type is used before the
67 // definition is received. Note: QRemoteObjectDynamicReplica doesn't include the
68 // QObject macro, so it's metaobject would resolve to QRemoteObjectReplica::metaObject()
69 // if we weren't overriding it.
70 if (!impl->m_metaObject) {
71 qWarning() << "Dynamic metaobject is not assigned, returning generic Replica metaObject.";
72 qWarning() << "This may cause issues if used for more than checking the Replica state.";
73 return QRemoteObjectReplica::metaObject();
74 }
75
76 return impl->m_metaObject;
77}
78
79/*!
80 \internal
81 This function overrides the QObject::qt_metacast() virtual function to provide the same functionality for dynamic replicas.
82
83 \sa QObject::qt_metacast()
84*/
85void *QRemoteObjectDynamicReplica::qt_metacast(const char *name)
86{
87 if (!name)
88 return nullptr;
89
90 if (!strcmp(s1: name, s2: "QRemoteObjectDynamicReplica"))
91 return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
92
93 // not entirely sure that one is needed... TODO: check
94 auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(src: d_impl);
95 if (QString::fromLatin1(ba: name) == impl->m_objectName)
96 return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
97
98 return QObject::qt_metacast(name);
99}
100
101/*!
102 \internal
103 This function overrides the QObject::qt_metacall() virtual function to provide the same functionality for dynamic replicas.
104
105 \sa QObject::qt_metacall()
106*/
107int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, void **argv)
108{
109 static const bool debugArgs = qEnvironmentVariableIsSet(varName: "QT_REMOTEOBJECT_DEBUG_ARGUMENTS");
110
111 auto impl = qSharedPointerCast<QConnectedReplicaImplementation>(src: d_impl);
112
113 int saved_id = id;
114 id = QRemoteObjectReplica::qt_metacall(call, id, argv);
115 if (id < 0 || impl->m_metaObject == nullptr)
116 return id;
117
118 if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
119 QMetaProperty mp = metaObject()->property(index: saved_id);
120
121 if (call == QMetaObject::WriteProperty) {
122 QVariantList args;
123 if (mp.userType() == QMetaType::QVariant)
124 args << *reinterpret_cast<QVariant*>(argv[0]);
125 else
126 args << QVariant(mp.metaType(), argv[0]);
127 QRemoteObjectReplica::send(call: QMetaObject::WriteProperty, index: saved_id, args);
128 } else {
129 if (mp.userType() == QMetaType::QVariant)
130 *reinterpret_cast<QVariant*>(argv[0]) = impl->m_propertyStorage[id];
131 else {
132 const QVariant value = propAsVariant(i: id);
133 mp.metaType().destruct(data: argv[0]);
134 mp.metaType().construct(where: argv[0], copy: value.data());
135 }
136 }
137
138 id = -1;
139 } else if (call == QMetaObject::InvokeMetaMethod) {
140 if (id < impl->m_numSignals) {
141 qCDebug(QT_REMOTEOBJECT) << "DynamicReplica Activate" << impl->m_metaObject->method(index: saved_id).methodSignature();
142 // signal relay from Source world to Replica
143 QMetaObject::activate(sender: this, impl->m_metaObject, local_signal_index: id, argv);
144
145 } else {
146 // method relay from Replica to Source
147 const QMetaMethod mm = impl->m_metaObject->method(index: saved_id);
148 const int nParam = mm.parameterCount();
149 QVariantList args;
150 args.reserve(asize: nParam);
151 for (int i = 0; i < nParam; ++i) {
152 const auto metaType = mm.parameterMetaType(index: i);
153 if (metaType.flags().testFlag(flag: QMetaType::IsEnumeration)) {
154 auto transferType = QRemoteObjectPackets::transferTypeForEnum(enumType: metaType);
155 args.push_back(t: QVariant(transferType, argv[i + 1]));
156 } else
157 args.push_back(t: QVariant(metaType, argv[i + 1]));
158 }
159
160 if (debugArgs) {
161 qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked - args:" << args;
162 } else {
163 qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked";
164 }
165
166 if (mm.returnType() == QMetaType::Void)
167 QRemoteObjectReplica::send(call: QMetaObject::InvokeMetaMethod, index: saved_id, args);
168 else {
169 QRemoteObjectPendingCall call = QRemoteObjectReplica::sendWithReply(call: QMetaObject::InvokeMetaMethod, index: saved_id, args);
170 if (argv[0])
171 *(static_cast<QRemoteObjectPendingCall*>(argv[0])) = call;
172 }
173 }
174
175 id = -1;
176 }
177
178 return id;
179}
180
181QT_END_NAMESPACE
182

source code of qtremoteobjects/src/remoteobjects/qremoteobjectdynamicreplica.cpp