1 | // Copyright (C) 2021 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 | |
4 | #ifndef QTREMOTEOBJECTPACKET_P_H |
5 | #define QTREMOTEOBJECTPACKET_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qtremoteobjectglobal.h" |
19 | #include "qremoteobjectsource.h" |
20 | #include "qconnectionfactories.h" |
21 | |
22 | #include <QtCore/qassociativeiterable.h> |
23 | #include <QtCore/qhash.h> |
24 | #include <QtCore/qmap.h> |
25 | #include <QtCore/qpair.h> |
26 | #include <QtCore/qsequentialiterable.h> |
27 | #include <QtCore/qurl.h> |
28 | #include <QtCore/qvariant.h> |
29 | #include <QtCore/qloggingcategory.h> |
30 | #include <QtCore/qdatastream.h> |
31 | #include <QtCore/private/qglobal_p.h> |
32 | |
33 | #include <cstdlib> |
34 | |
35 | QT_BEGIN_NAMESPACE |
36 | |
37 | class QMetaObjectBuilder; |
38 | class QRemoteObjectSourceBase; |
39 | class QRemoteObjectRootSource; |
40 | |
41 | namespace QRemoteObjectPackets { |
42 | |
43 | Q_NAMESPACE |
44 | |
45 | class DataStreamPacket; |
46 | |
47 | struct ObjectInfo |
48 | { |
49 | QString name; |
50 | QString typeName; |
51 | QByteArray signature; |
52 | }; |
53 | |
54 | inline QDebug operator<<(QDebug dbg, const ObjectInfo &info) |
55 | { |
56 | dbg.nospace() << "ObjectInfo(" << info.name << ", " << info.typeName << ", " << info.signature <<")" ; |
57 | return dbg.space(); |
58 | } |
59 | |
60 | inline QDataStream& operator<<(QDataStream &stream, const ObjectInfo &info) |
61 | { |
62 | return stream << info.name << info.typeName << info.signature; |
63 | } |
64 | |
65 | inline QDataStream& operator>>(QDataStream &stream, ObjectInfo &info) |
66 | { |
67 | return stream >> info.name >> info.typeName >> info.signature; |
68 | } |
69 | |
70 | using ObjectInfoList = QList<ObjectInfo>; |
71 | |
72 | enum class ObjectType : quint8 { CLASS, MODEL, GADGET }; |
73 | Q_ENUM_NS(ObjectType) |
74 | |
75 | // Use a short name, as QVariant::save writes the name every time a qvariant of |
76 | // this type is serialized |
77 | class QRO_ |
78 | { |
79 | public: |
80 | QRO_() : type(ObjectType::CLASS), isNull(true) {} |
81 | explicit QRO_(QRemoteObjectSourceBase *source); |
82 | explicit QRO_(const QVariant &value); |
83 | QString name, typeName; |
84 | ObjectType type; |
85 | bool isNull; |
86 | QByteArray classDefinition; |
87 | QByteArray parameters; |
88 | }; |
89 | |
90 | inline QDebug operator<<(QDebug dbg, const QRO_ &info) |
91 | { |
92 | dbg.nospace() << "QRO_(name: " << info.name << ", typeName: " << info.typeName |
93 | << ", type: " << info.type << ", valid: " << (info.isNull ? "true" : "false" ) |
94 | << ", parameters: {" << info.parameters << ")" |
95 | << (info.classDefinition.isEmpty() ? " no definitions)" : " with definitions)" ); |
96 | return dbg.space(); |
97 | } |
98 | |
99 | QDataStream& operator<<(QDataStream &stream, const QRO_ &info); |
100 | |
101 | QDataStream& operator>>(QDataStream &stream, QRO_ &info); |
102 | |
103 | // Class for transmitting sequence data. Needed because containers for custom |
104 | // types (and even primitive types in Qt5) are not registered with the metaObject |
105 | // system. This wrapper allows us to create the desired container if it is |
106 | // registered, or a QtROSequentialContainer if it is not. QtROSequentialContainer |
107 | // is derived from QVariantList, so it can be used from QML similar to the API |
108 | // type. |
109 | class QSQ_ |
110 | { |
111 | public: |
112 | QSQ_() {} |
113 | explicit QSQ_(const QVariant &lst); |
114 | QByteArray typeName, valueTypeName; |
115 | QByteArray values; |
116 | }; |
117 | |
118 | inline QDebug operator<<(QDebug dbg, const QSQ_ &seq) |
119 | { |
120 | dbg.nospace() << "QSQ_(typeName: " << seq.typeName << ", valueType: " << seq.valueTypeName |
121 | << ", values: {" << seq.values <<")" ; |
122 | return dbg.space(); |
123 | } |
124 | |
125 | QDataStream& operator<<(QDataStream &stream, const QSQ_ &info); |
126 | |
127 | QDataStream& operator>>(QDataStream &stream, QSQ_ &info); |
128 | |
129 | // Class for transmitting associative containers. Needed because containers for |
130 | // custom types (and even primitive types in Qt5) are not registered with the |
131 | // metaObject system. This wrapper allows us to create the desired container if |
132 | // it is registered, or a QtROAssociativeContainer if it is not. |
133 | // QtROAssociativeContainer is derived from QVariantMap, so it can be used from |
134 | // QML similar to the API type. |
135 | class QAS_ |
136 | { |
137 | public: |
138 | QAS_() {} |
139 | explicit QAS_(const QVariant &lst); |
140 | QByteArray typeName, keyTypeName, valueTypeName; |
141 | QByteArray values; |
142 | }; |
143 | |
144 | inline QDebug operator<<(QDebug dbg, const QAS_ &seq) |
145 | { |
146 | dbg.nospace() << "QAS_(typeName: " << seq.typeName << ", keyType: " << seq.keyTypeName |
147 | << ", valueType: " << seq.valueTypeName << ", values: {" << seq.values <<")" ; |
148 | return dbg.space(); |
149 | } |
150 | |
151 | QDataStream& operator<<(QDataStream &stream, const QAS_ &info); |
152 | |
153 | QDataStream& operator>>(QDataStream &stream, QAS_ &info); |
154 | |
155 | //Helper class for creating a QByteArray from a QRemoteObjectPacket |
156 | class DataStreamPacket : public QDataStream |
157 | { |
158 | public: |
159 | DataStreamPacket(quint16 id = QtRemoteObjects::InvokePacket); |
160 | |
161 | void setId(quint16 id) |
162 | { |
163 | device()->seek(pos: baseAddress); |
164 | *this << quint32(0); |
165 | *this << id; |
166 | } |
167 | |
168 | void finishPacket() |
169 | { |
170 | size = device()->pos(); |
171 | device()->seek(pos: baseAddress); |
172 | *this << quint32(size - baseAddress - sizeof(quint32)); |
173 | baseAddress = size; // Allow appending until reset() is called |
174 | } |
175 | |
176 | const QByteArray &payload() |
177 | { |
178 | array.resize(size); |
179 | return array; |
180 | } |
181 | |
182 | void reset() |
183 | { |
184 | baseAddress = 0; |
185 | size = 0; |
186 | array.clear(); |
187 | } |
188 | |
189 | private: |
190 | QByteArray array; |
191 | int baseAddress; |
192 | int size; |
193 | |
194 | Q_DISABLE_COPY(DataStreamPacket) |
195 | }; |
196 | |
197 | class CodecBase |
198 | { |
199 | public: |
200 | CodecBase() = default; |
201 | CodecBase(const CodecBase &) = default; |
202 | CodecBase(CodecBase &&) = default; |
203 | CodecBase &operator=(const CodecBase &) = default; |
204 | CodecBase &operator=(CodecBase &&) = default; |
205 | virtual ~CodecBase() = default; |
206 | |
207 | virtual void serializeObjectListPacket(const ObjectInfoList &) = 0; |
208 | virtual void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) = 0; |
209 | virtual void serializeInitPacket(const QRemoteObjectRootSource *) = 0; |
210 | virtual void serializeInitDynamicPacket(const QRemoteObjectRootSource *) = 0; |
211 | virtual void serializePropertyChangePacket(QRemoteObjectSourceBase *source, |
212 | int signalIndex) = 0; |
213 | virtual void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) = 0; |
214 | virtual void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) = 0; |
215 | // Heartbeat packets |
216 | virtual void serializePingPacket(const QString &name) = 0; |
217 | virtual void serializePongPacket(const QString &name) = 0; |
218 | virtual void serializeInvokePacket(const QString &name, int call, int index, |
219 | const QVariantList &args, int serialId = -1, |
220 | int propertyIndex = -1) = 0; |
221 | virtual void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args, |
222 | int &serialId, int &propertyIndex) = 0; |
223 | virtual void serializeInvokeReplyPacket(const QString &name, int ackedSerialId, |
224 | const QVariant &value) = 0; |
225 | virtual void serializeHandshakePacket() = 0; |
226 | virtual void serializeRemoveObjectPacket(const QString &name) = 0; |
227 | //There is no deserializeRemoveObjectPacket - no parameters other than id and name |
228 | virtual void serializeAddObjectPacket(const QString &name, bool isDynamic) = 0; |
229 | virtual void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) = 0; |
230 | virtual void deserializeInitPacket(QDataStream &, QVariantList &) = 0; |
231 | virtual void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId, |
232 | QVariant &value) = 0; |
233 | void send(const QSet<QtROIoDeviceBase *> &connections); |
234 | void send(const QVector<QtROIoDeviceBase *> &connections); |
235 | void send(QtROIoDeviceBase *connection); |
236 | |
237 | protected: |
238 | // A payload can consist of one or more packets |
239 | virtual const QByteArray &getPayload() = 0; |
240 | virtual void reset() {} |
241 | }; |
242 | |
243 | class QDataStreamCodec : public CodecBase |
244 | { |
245 | public: |
246 | void serializeObjectListPacket(const ObjectInfoList &) override; |
247 | void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) override; |
248 | void serializeInitPacket(const QRemoteObjectRootSource *) override; |
249 | void serializeInitDynamicPacket(const QRemoteObjectRootSource*) override; |
250 | void serializePropertyChangePacket(QRemoteObjectSourceBase *source, int signalIndex) override; |
251 | void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) override; |
252 | void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) override; |
253 | void serializePingPacket(const QString &name) override; |
254 | void serializePongPacket(const QString &name) override; |
255 | void serializeInvokePacket(const QString &name, int call, int index, const QVariantList &args, |
256 | int serialId = -1, int propertyIndex = -1) override; |
257 | void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args, |
258 | int &serialId, int &propertyIndex) override; |
259 | void serializeInvokeReplyPacket(const QString &name, int ackedSerialId, |
260 | const QVariant &value) override; |
261 | void serializeHandshakePacket() override; |
262 | void serializeRemoveObjectPacket(const QString &name) override; |
263 | void serializeAddObjectPacket(const QString &name, bool isDynamic) override; |
264 | void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) override; |
265 | void deserializeInitPacket(QDataStream &, QVariantList &) override; |
266 | void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId, |
267 | QVariant &value) override; |
268 | |
269 | protected: |
270 | const QByteArray &getPayload() override { |
271 | return m_packet.payload(); |
272 | } |
273 | void reset() override { |
274 | m_packet.reset(); |
275 | } |
276 | private: |
277 | void serializeDefinition(QDataStream &, const QRemoteObjectSourceBase *); |
278 | void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex); |
279 | void serializeProperties(const QRemoteObjectSourceBase *source); |
280 | DataStreamPacket m_packet; |
281 | }; |
282 | |
283 | QMetaType transferTypeForEnum(QMetaType enumType); |
284 | QVariant encodeVariant(const QVariant &value); |
285 | QVariant decodeVariant(QVariant &&value, QMetaType metaType); |
286 | |
287 | } // namespace QRemoteObjectPackets |
288 | |
289 | QT_END_NAMESPACE |
290 | |
291 | QT_DECL_METATYPE_EXTERN_TAGGED(QRemoteObjectPackets::QRO_, QRemoteObjectPackets__QRO_, |
292 | /* not exported */) |
293 | |
294 | #endif |
295 | |