1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Viktor Kopp <vifactor@gmail.com> |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include "qprotobufserializer.h" |
6 | #include "qprotobufserializer_p.h" |
7 | |
8 | #include "qtprotobuftypes.h" |
9 | |
10 | #include <QtCore/qmetatype.h> |
11 | #include <QtCore/qcoreapplication.h> |
12 | #include <QtCore/qmetaobject.h> |
13 | #include <QtCore/qvariant.h> |
14 | #include <QtCore/qreadwritelock.h> |
15 | |
16 | #include <QtProtobuf/private/qprotobufserializer_p.h> |
17 | #include <QtProtobuf/private/qprotobufmessage_p.h> |
18 | |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | namespace { |
23 | |
24 | /* |
25 | \internal |
26 | \brief The HandlersRegistry is a container to store mapping between metatype |
27 | identifier and serialization handlers. |
28 | */ |
29 | struct HandlersRegistry |
30 | { |
31 | void registerHandler(QMetaType type, const QtProtobufPrivate::SerializationHandler &handlers) |
32 | { |
33 | QWriteLocker locker(&m_lock); |
34 | m_registry[type] = handlers; |
35 | } |
36 | |
37 | QtProtobufPrivate::SerializationHandler findHandler(QMetaType type) |
38 | { |
39 | QtProtobufPrivate::SerializationHandler handler; |
40 | QReadLocker locker(&m_lock); |
41 | auto it = m_registry.constFind(key: type); |
42 | if (it != m_registry.constEnd()) |
43 | handler = it.value(); |
44 | return handler; |
45 | } |
46 | |
47 | private: |
48 | QReadWriteLock m_lock; |
49 | QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry; |
50 | }; |
51 | Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry) |
52 | |
53 | inline bool isOneofField(const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) |
54 | { |
55 | // TODO: Add the check for the optional flag once the functionality is |
56 | // implemented. |
57 | return fieldInfo.getFieldFlags() & QtProtobufPrivate::Oneof; |
58 | } |
59 | |
60 | } // namespace |
61 | |
62 | void QtProtobufPrivate::registerHandler(QMetaType type, |
63 | const QtProtobufPrivate::SerializationHandler &handlers) |
64 | { |
65 | handlersRegistry->registerHandler(type, handlers); |
66 | } |
67 | |
68 | QtProtobufPrivate::SerializationHandler QtProtobufPrivate::findHandler(QMetaType type) |
69 | { |
70 | if (!handlersRegistry.exists()) |
71 | return {}; |
72 | return handlersRegistry->findHandler(type); |
73 | } |
74 | |
75 | /*! |
76 | \class QProtobufSerializer |
77 | \inmodule QtProtobuf |
78 | \since 6.5 |
79 | \brief The QProtobufSerializer class is interface that represents |
80 | basic functions for serialization/deserialization. |
81 | \reentrant |
82 | |
83 | The QProtobufSerializer class registers serializers/deserializers for |
84 | classes implementing a protobuf message, inheriting QProtobufMessage. These |
85 | classes are generated automatically, based on a .proto file, using the cmake |
86 | build macro qt6_add_protobuf or by running qtprotobufgen directly. |
87 | */ |
88 | |
89 | /*! |
90 | \fn QProtobufSerializer::DeserializationError QProtobufSerializer::deserializationError() const |
91 | |
92 | Returns the last deserialization error. |
93 | */ |
94 | |
95 | /*! |
96 | \fn QString QProtobufSerializer::deserializationErrorString() const |
97 | |
98 | Returns a human-readable string describing the last deserialization error. |
99 | If there was no error, an empty string is returned. |
100 | */ |
101 | |
102 | /*! |
103 | \relates QProtobufSerializer |
104 | \fn template<typename T> inline void qRegisterProtobufType() |
105 | |
106 | Registers a Protobuf type \e T. |
107 | This function is normally called by generated code. |
108 | */ |
109 | |
110 | /*! |
111 | \relates QProtobufSerializer |
112 | \fn template<typename K, typename V> inline void qRegisterProtobufMapType(); |
113 | |
114 | Registers a Protobuf map type \c K and \c V. |
115 | \c V must be a QProtobufMessage. |
116 | This function is normally called by generated code. |
117 | */ |
118 | |
119 | /*! |
120 | \relates QProtobufSerializer |
121 | \fn template<typename T> inline void qRegisterProtobufEnumType(); |
122 | |
123 | Registers serializers for enumeration type \c T in QtProtobuf global |
124 | serializers registry. |
125 | |
126 | This function is normally called by generated code. |
127 | */ |
128 | |
129 | using namespace Qt::StringLiterals; |
130 | using namespace QtProtobufPrivate; |
131 | |
132 | template<std::size_t N> |
133 | using SerializerRegistryType = |
134 | std::array<QProtobufSerializerPrivate::ProtobufSerializationHandler, N>; |
135 | |
136 | namespace { |
137 | #define QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(Type, WireType) \ |
138 | { \ |
139 | QMetaType::fromType<Type>(), \ |
140 | QProtobufSerializerPrivate::serializeWrapper< \ |
141 | Type, QProtobufSerializerPrivate::serializeBasic<Type>>, \ |
142 | QProtobufSerializerPrivate::deserializeBasic<Type>, \ |
143 | QProtobufSerializerPrivate::isPresent<Type>, WireType \ |
144 | } |
145 | #define QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(ListType, Type) \ |
146 | { \ |
147 | QMetaType::fromType<ListType>(), \ |
148 | QProtobufSerializerPrivate::serializeWrapper< \ |
149 | ListType, QProtobufSerializerPrivate::serializeListType<Type>>, \ |
150 | QProtobufSerializerPrivate::deserializeList<Type>, \ |
151 | QProtobufSerializerPrivate::isPresent<ListType>, \ |
152 | QtProtobuf::WireTypes::LengthDelimited \ |
153 | } |
154 | |
155 | #define QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(ListType, Type, WireType) \ |
156 | { \ |
157 | QMetaType::fromType<ListType>(), \ |
158 | QProtobufSerializerPrivate::serializeNonPackedWrapper< \ |
159 | ListType, QProtobufSerializerPrivate::serializeNonPackedList<Type>>, \ |
160 | QProtobufSerializerPrivate::deserializeNonPackedList<Type>, \ |
161 | QProtobufSerializerPrivate::isPresent<ListType>, WireType \ |
162 | } |
163 | |
164 | constexpr SerializerRegistryType<30> IntegratedTypesSerializers = { ._M_elems: { |
165 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(float, QtProtobuf::WireTypes::Fixed32), |
166 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(double, QtProtobuf::WireTypes::Fixed64), |
167 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int32, |
168 | QtProtobuf::WireTypes::Varint), |
169 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int64, |
170 | QtProtobuf::WireTypes::Varint), |
171 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint32, |
172 | QtProtobuf::WireTypes::Varint), |
173 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint64, |
174 | QtProtobuf::WireTypes::Varint), |
175 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint32, |
176 | QtProtobuf::WireTypes::Varint), |
177 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint64, |
178 | QtProtobuf::WireTypes::Varint), |
179 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed32, |
180 | QtProtobuf::WireTypes::Fixed32), |
181 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed64, |
182 | QtProtobuf::WireTypes::Fixed64), |
183 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed32, |
184 | QtProtobuf::WireTypes::Fixed32), |
185 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed64, |
186 | QtProtobuf::WireTypes::Fixed64), |
187 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::boolean, |
188 | QtProtobuf::WireTypes::Varint), |
189 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QString, |
190 | QtProtobuf::WireTypes::LengthDelimited), |
191 | QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QByteArray, |
192 | QtProtobuf::WireTypes::LengthDelimited), |
193 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float), |
194 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double), |
195 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int32List, QtProtobuf::int32), |
196 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int64List, QtProtobuf::int64), |
197 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint32List, |
198 | QtProtobuf::uint32), |
199 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint64List, |
200 | QtProtobuf::uint64), |
201 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint32List, |
202 | QtProtobuf::sint32), |
203 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint64List, |
204 | QtProtobuf::sint64), |
205 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed32List, |
206 | QtProtobuf::fixed32), |
207 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed64List, |
208 | QtProtobuf::fixed64), |
209 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed32List, |
210 | QtProtobuf::sfixed32), |
211 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed64List, |
212 | QtProtobuf::sfixed64), |
213 | QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::boolList, QtProtobuf::boolean), |
214 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
215 | QStringList, QString, QtProtobuf::WireTypes::LengthDelimited), |
216 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
217 | QByteArrayList, QByteArray, QtProtobuf::WireTypes::LengthDelimited), |
218 | } }; |
219 | |
220 | constexpr SerializerRegistryType<13> IntegratedNonPackedSerializers = { ._M_elems: { |
221 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float, |
222 | QtProtobuf::WireTypes::Fixed32), |
223 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double, |
224 | QtProtobuf::WireTypes::Fixed64), |
225 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
226 | QtProtobuf::int32List, QtProtobuf::int32, QtProtobuf::WireTypes::Varint), |
227 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
228 | QtProtobuf::int64List, QtProtobuf::int64, QtProtobuf::WireTypes::Varint), |
229 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
230 | QtProtobuf::uint32List, QtProtobuf::uint32, QtProtobuf::WireTypes::Varint), |
231 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
232 | QtProtobuf::uint64List, QtProtobuf::uint64, QtProtobuf::WireTypes::Varint), |
233 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
234 | QtProtobuf::sint32List, QtProtobuf::sint32, QtProtobuf::WireTypes::Varint), |
235 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
236 | QtProtobuf::sint64List, QtProtobuf::sint64, QtProtobuf::WireTypes::Varint), |
237 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
238 | QtProtobuf::fixed32List, QtProtobuf::fixed32, QtProtobuf::WireTypes::Fixed32), |
239 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
240 | QtProtobuf::fixed64List, QtProtobuf::fixed64, QtProtobuf::WireTypes::Fixed64), |
241 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
242 | QtProtobuf::sfixed32List, QtProtobuf::sfixed32, QtProtobuf::WireTypes::Fixed32), |
243 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
244 | QtProtobuf::sfixed64List, QtProtobuf::sfixed64, QtProtobuf::WireTypes::Fixed64), |
245 | QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( |
246 | QtProtobuf::boolList, QtProtobuf::boolean, QtProtobuf::WireTypes::Varint), |
247 | } }; |
248 | |
249 | template<std::size_t N> |
250 | std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler> |
251 | findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType<N> ®istry) |
252 | { |
253 | typename SerializerRegistryType<N>::const_iterator it = std::find_if( |
254 | registry.begin(), registry.end(), |
255 | [&metaType](const QProtobufSerializerPrivate::ProtobufSerializationHandler &handler) { |
256 | return handler.metaType == metaType; |
257 | }); |
258 | if (it == registry.end()) |
259 | return std::nullopt; |
260 | return { *it }; |
261 | } |
262 | |
263 | std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler> |
264 | findIntegratedTypeHandler(QMetaType metaType, bool nonPacked) |
265 | { |
266 | if (nonPacked) |
267 | return findIntegratedTypeHandlerImpl(metaType, registry: IntegratedNonPackedSerializers); |
268 | |
269 | return findIntegratedTypeHandlerImpl(metaType, registry: IntegratedTypesSerializers); |
270 | } |
271 | } |
272 | |
273 | /*! |
274 | Constructs a new serializer instance. |
275 | */ |
276 | QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate(this)) |
277 | { |
278 | } |
279 | |
280 | /*! |
281 | Destroys the serializer instance. |
282 | */ |
283 | QProtobufSerializer::~QProtobufSerializer() = default; |
284 | |
285 | /*! |
286 | This is called by serialize() to serialize a registered Protobuf message |
287 | \a message with \a ordering. \a message must not be |
288 | \nullptr. |
289 | Returns a QByteArray containing the serialized message. |
290 | */ |
291 | QByteArray QProtobufSerializer::serializeMessage( |
292 | const QProtobufMessage *message, |
293 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering) const |
294 | { |
295 | QByteArray result; |
296 | for (int index = 0; index < ordering.fieldCount(); ++index) { |
297 | int fieldIndex = ordering.getFieldNumber(index); |
298 | Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, "" , "fieldIndex is out of range" ); |
299 | QProtobufPropertyOrderingInfo fieldInfo(ordering, index); |
300 | QVariant propertyValue = message->property(fieldInfo); |
301 | result.append(a: d_ptr->serializeProperty(propertyValue, fieldInfo)); |
302 | } |
303 | |
304 | // Restore any unknown fields we have stored away: |
305 | const QProtobufMessagePrivate *messagePrivate = QProtobufMessagePrivate::get(message); |
306 | for (const auto &[bytes, occurrences] : messagePrivate->unknownEntries.asKeyValueRange()) |
307 | result += bytes.repeated(times: occurrences); |
308 | |
309 | return result; |
310 | } |
311 | |
312 | void QProtobufSerializerPrivate::setUnexpectedEndOfStreamError() |
313 | { |
314 | setDeserializationError(error: QAbstractProtobufSerializer::UnexpectedEndOfStreamError, |
315 | errorString: QCoreApplication::translate(context: "QtProtobuf" , key: "Unexpected end of stream" )); |
316 | } |
317 | |
318 | void QProtobufSerializerPrivate::clearError() |
319 | { |
320 | deserializationError = QAbstractProtobufSerializer::NoError; |
321 | deserializationErrorString.clear(); |
322 | } |
323 | |
324 | /*! |
325 | This is called by deserialize() to deserialize a registered Protobuf message |
326 | \a message with \a ordering, from a QByteArrayView \a data. \a message |
327 | can be assumed to not be \nullptr. |
328 | Returns \c true if deserialization was successful, otherwise \c false. |
329 | */ |
330 | bool QProtobufSerializer::deserializeMessage( |
331 | QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
332 | QByteArrayView data) const |
333 | { |
334 | d_ptr->clearError(); |
335 | auto it = QProtobufSelfcheckIterator::fromView(container: data); |
336 | while (it.isValid() && it != data.end()) { |
337 | if (!d_ptr->deserializeProperty(message, ordering, it)) |
338 | return false; |
339 | } |
340 | if (!it.isValid()) |
341 | d_ptr->setUnexpectedEndOfStreamError(); |
342 | return it.isValid(); |
343 | } |
344 | |
345 | /*! |
346 | Serialize an \a message with \a ordering and \a fieldInfo. |
347 | Returns a QByteArray containing the serialized message. |
348 | |
349 | You should not call this function directly. |
350 | */ |
351 | QByteArray |
352 | QProtobufSerializer::serializeObject(const QProtobufMessage *message, |
353 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
354 | const QProtobufPropertyOrderingInfo &fieldInfo) const |
355 | { |
356 | QByteArray result = QProtobufSerializerPrivate::prependLengthDelimitedSize( |
357 | data: serializeMessage(message, ordering)); |
358 | result.prepend(a: QProtobufSerializerPrivate::encodeHeader( |
359 | fieldIndex: fieldInfo.getFieldNumber(), wireType: QtProtobuf::WireTypes::LengthDelimited)); |
360 | return result; |
361 | } |
362 | |
363 | /*! |
364 | Deserialize an \a message with \a ordering from a QProtobufSelfcheckIterator |
365 | \a it. Returns \c true if deserialization was successful, otherwise |
366 | \c false. |
367 | |
368 | You should not call this function directly. |
369 | */ |
370 | bool QProtobufSerializer::deserializeObject(QProtobufMessage *message, |
371 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
372 | QProtobufSelfcheckIterator &it) const |
373 | { |
374 | if (it.bytesLeft() == 0) { |
375 | d_ptr->setUnexpectedEndOfStreamError(); |
376 | return false; |
377 | } |
378 | std::optional<QByteArray> array = QProtobufSerializerPrivate::deserializeLengthDelimited(it); |
379 | if (!array) { |
380 | d_ptr->setUnexpectedEndOfStreamError(); |
381 | return false; |
382 | } |
383 | return deserializeMessage(message, ordering, data: array.value()); |
384 | } |
385 | |
386 | /*! |
387 | This function is called to serialize \a message as a part of list property |
388 | with \a ordering and \a fieldInfo. |
389 | |
390 | You should not call this function directly. |
391 | */ |
392 | QByteArray QProtobufSerializer::serializeListObject( |
393 | const QProtobufMessage *message, |
394 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
395 | const QProtobufPropertyOrderingInfo &fieldInfo) const |
396 | { |
397 | return serializeObject(message, ordering, fieldInfo); |
398 | } |
399 | |
400 | /*! |
401 | This function deserializes an \a message from byte stream as part of list property, with |
402 | \a ordering from a QProtobufSelfcheckIterator \a it. |
403 | Returns \c true if deserialization was successful, otherwise \c false. |
404 | |
405 | You should not call this function directly. |
406 | */ |
407 | bool QProtobufSerializer::deserializeListObject(QProtobufMessage *message, |
408 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
409 | QProtobufSelfcheckIterator &it) const |
410 | { |
411 | return deserializeObject(message, ordering, it); |
412 | } |
413 | |
414 | /*! |
415 | This function serializes QMap pair of \a key and \a value with |
416 | \a fieldInfo to a QByteArray |
417 | |
418 | You should not call this function directly. |
419 | */ |
420 | QByteArray |
421 | QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, |
422 | const QProtobufPropertyOrderingInfo &fieldInfo) const |
423 | { |
424 | auto keyHandler = findIntegratedTypeHandler(metaType: key.metaType(), nonPacked: false); |
425 | Q_ASSERT_X(keyHandler, "QProtobufSerializer" , "Map key is not an integrated type." ); |
426 | |
427 | QByteArray result = QProtobufSerializerPrivate::encodeHeader( |
428 | fieldIndex: fieldInfo.getFieldNumber(), wireType: QtProtobuf::WireTypes::LengthDelimited); |
429 | |
430 | result.append(a: QProtobufSerializerPrivate::prependLengthDelimitedSize( |
431 | data: keyHandler->serializer( |
432 | key, QProtobufSerializerPrivate::encodeHeader(fieldIndex: 1, wireType: keyHandler->wireType)) |
433 | + d_ptr->serializeProperty(propertyValue: value, fieldInfo: fieldInfo.infoForMapValue()))); |
434 | return result; |
435 | } |
436 | |
437 | /*! |
438 | This function deserializes QMap pair of \a key and \a value from a |
439 | QProtobufSelfcheckIterator \a it. |
440 | Returns \c true if deserialization was successful, otherwise \c false. |
441 | |
442 | You should not call this function directly. |
443 | */ |
444 | bool QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const |
445 | { |
446 | return d_ptr->deserializeMapPair(key, value, it); |
447 | } |
448 | |
449 | /*! |
450 | This function serializes \a value as a QByteArray for enum associated with |
451 | property \a fieldInfo. |
452 | |
453 | You should not call this function directly. |
454 | */ |
455 | QByteArray QProtobufSerializer::serializeEnum(QtProtobuf::int64 value, |
456 | const QProtobufPropertyOrderingInfo &fieldInfo) const |
457 | { |
458 | if (value == 0 && !isOneofField(fieldInfo)) |
459 | return {}; |
460 | |
461 | QtProtobuf::WireTypes type = QtProtobuf::WireTypes::Varint; |
462 | int fieldNumber = fieldInfo.getFieldNumber(); |
463 | return QProtobufSerializerPrivate::encodeHeader(fieldIndex: fieldNumber, wireType: type) |
464 | + QProtobufSerializerPrivate::serializeBasic<QtProtobuf::int64>(value); |
465 | } |
466 | |
467 | /*! |
468 | This function serializes a list, \a value, as a QByteArray for enum |
469 | associated with property \a fieldInfo. |
470 | |
471 | You should not call this function directly. |
472 | */ |
473 | QByteArray |
474 | QProtobufSerializer::serializeEnumList(const QList<QtProtobuf::int64> &value, |
475 | const QProtobufPropertyOrderingInfo &fieldInfo) const |
476 | { |
477 | if (value.isEmpty()) { |
478 | return {}; |
479 | } |
480 | |
481 | auto = QProtobufSerializerPrivate::encodeHeader(fieldIndex: fieldInfo.getFieldNumber(), |
482 | wireType: QtProtobuf::WireTypes::LengthDelimited); |
483 | |
484 | if (fieldInfo.getFieldFlags() & QtProtobufPrivate::NonPacked) |
485 | return QProtobufSerializerPrivate::serializeNonPackedList<QtProtobuf::int64>(listValue: value, header); |
486 | |
487 | return header + QProtobufSerializerPrivate::serializeListType<QtProtobuf::int64>(listValue: value); |
488 | } |
489 | |
490 | /*! |
491 | This function deserializes an enum \a value from a QProtobufSelfcheckIterator \a it. |
492 | Returns \c true if deserialization was successful, otherwise \c false. |
493 | |
494 | You should not call this function directly. |
495 | */ |
496 | bool QProtobufSerializer::deserializeEnum(QtProtobuf::int64 &value, QProtobufSelfcheckIterator &it) const |
497 | { |
498 | QVariant variantValue; |
499 | if (!QProtobufSerializerPrivate::deserializeBasic<QtProtobuf::int64>(it, variantValue)) { |
500 | d_ptr->setUnexpectedEndOfStreamError(); |
501 | return false; |
502 | } |
503 | value = variantValue.value<QtProtobuf::int64>(); |
504 | return true; |
505 | } |
506 | |
507 | /*! |
508 | This function deserializes a list of enum \a value from a QProtobufSelfcheckIterator \a it. |
509 | Returns \c true if deserialization was successful, otherwise \c false. |
510 | |
511 | You should not call this function directly. |
512 | */ |
513 | bool QProtobufSerializer::deserializeEnumList(QList<QtProtobuf::int64> &value, QProtobufSelfcheckIterator &it) const |
514 | { |
515 | QVariant variantValue; |
516 | if (!QProtobufSerializerPrivate::deserializeList<QtProtobuf::int64>(it, previousValue&: variantValue)) { |
517 | d_ptr->setUnexpectedEndOfStreamError(); |
518 | return false; |
519 | } |
520 | value = variantValue.value<QList<QtProtobuf::int64>>(); |
521 | return true; |
522 | } |
523 | |
524 | QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q) |
525 | { |
526 | } |
527 | |
528 | /*! |
529 | Encode a property field index and its type into output bytes. |
530 | |
531 | Header byte |
532 | Meaning | Field index | Type |
533 | ---------- | ------------- | -------- |
534 | bit number | 7 6 5 4 3 | 2 1 0 |
535 | |
536 | fieldIndex: The index of a property in parent object |
537 | wireType: Serialization type used for the property with index @p fieldIndex |
538 | |
539 | Returns a varint-encoded fieldIndex and wireType |
540 | */ |
541 | QByteArray QProtobufSerializerPrivate::(int fieldIndex, |
542 | QtProtobuf::WireTypes wireType) |
543 | { |
544 | uint32_t = (fieldIndex << 3) | int(wireType); |
545 | return serializeVarintCommon<uint32_t>(value: header); |
546 | } |
547 | |
548 | /*! |
549 | Decode a property field index and its serialization type from input bytes |
550 | |
551 | Iterator: that points to header with encoded field index and serialization type |
552 | fieldIndex: Decoded index of a property in parent object |
553 | wireType: Decoded serialization type used for the property with index |
554 | * |
555 | \return true if both decoded wireType and fieldIndex have "allowed" values and false, otherwise |
556 | */ |
557 | bool QProtobufSerializerPrivate::(QProtobufSelfcheckIterator &it, |
558 | int &fieldIndex, |
559 | QtProtobuf::WireTypes &wireType) |
560 | { |
561 | if (it.bytesLeft() == 0) |
562 | return false; |
563 | auto opt = deserializeVarintCommon<uint32_t>(it); |
564 | if (!opt) |
565 | return false; |
566 | uint32_t = opt.value(); |
567 | wireType = static_cast<QtProtobuf::WireTypes>(header & 0b00000111); |
568 | fieldIndex = header >> 3; |
569 | |
570 | constexpr int maxFieldIndex = (1 << 29) - 1; |
571 | return fieldIndex <= maxFieldIndex && fieldIndex > 0 |
572 | && (wireType == QtProtobuf::WireTypes::Varint |
573 | || wireType == QtProtobuf::WireTypes::Fixed64 |
574 | || wireType == QtProtobuf::WireTypes::Fixed32 |
575 | || wireType == QtProtobuf::WireTypes::LengthDelimited); |
576 | } |
577 | |
578 | void QProtobufSerializerPrivate::skipVarint(QProtobufSelfcheckIterator &it) |
579 | { |
580 | while ((*it) & 0x80) |
581 | ++it; |
582 | ++it; |
583 | } |
584 | |
585 | void QProtobufSerializerPrivate::skipLengthDelimited(QProtobufSelfcheckIterator &it) |
586 | { |
587 | //Get length of length-delimited field |
588 | auto opt = QProtobufSerializerPrivate::deserializeVarintCommon<QtProtobuf::uint64>(it); |
589 | if (!opt) { |
590 | it += it.bytesLeft() + 1; |
591 | return; |
592 | } |
593 | QtProtobuf::uint64 length = opt.value(); |
594 | it += length; |
595 | } |
596 | |
597 | qsizetype QProtobufSerializerPrivate::skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, QtProtobuf::WireTypes type) |
598 | { |
599 | const auto *initialIt = QByteArray::const_iterator(it); |
600 | switch (type) { |
601 | case QtProtobuf::WireTypes::Varint: |
602 | skipVarint(it); |
603 | break; |
604 | case QtProtobuf::WireTypes::Fixed32: |
605 | it += sizeof(decltype(QtProtobuf::fixed32::_t)); |
606 | break; |
607 | case QtProtobuf::WireTypes::Fixed64: |
608 | it += sizeof(decltype(QtProtobuf::fixed64::_t)); |
609 | break; |
610 | case QtProtobuf::WireTypes::LengthDelimited: |
611 | skipLengthDelimited(it); |
612 | break; |
613 | case QtProtobuf::WireTypes::Unknown: |
614 | default: |
615 | Q_UNREACHABLE(); |
616 | return 0; |
617 | } |
618 | |
619 | return std::distance(first: initialIt, last: QByteArray::const_iterator(it)); |
620 | } |
621 | |
622 | QByteArray |
623 | QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue, |
624 | const QProtobufPropertyOrderingInfo &fieldInfo) |
625 | { |
626 | QMetaType metaType = propertyValue.metaType(); |
627 | |
628 | qProtoDebug() << "propertyValue" << propertyValue << "fieldIndex" << fieldInfo.getFieldNumber() |
629 | << "metaType" << metaType.name(); |
630 | |
631 | if (metaType.id() == QMetaType::UnknownType || propertyValue.isNull()) { |
632 | // Empty value |
633 | return {}; |
634 | } |
635 | |
636 | auto basicHandler = findIntegratedTypeHandler( |
637 | metaType, nonPacked: fieldInfo.getFieldFlags() & QtProtobufPrivate::NonPacked); |
638 | if (basicHandler) { |
639 | bool serializeUninitialized = isOneofField(fieldInfo); |
640 | if (!basicHandler->isPresent(propertyValue) && !serializeUninitialized) { |
641 | return {}; |
642 | } |
643 | |
644 | QByteArray = QProtobufSerializerPrivate::encodeHeader(fieldIndex: fieldInfo.getFieldNumber(), |
645 | wireType: basicHandler->wireType); |
646 | return basicHandler->serializer(propertyValue, header); |
647 | } |
648 | |
649 | auto handler = QtProtobufPrivate::findHandler(type: metaType); |
650 | if (!handler.serializer) { |
651 | qProtoWarning() << "No serializer for type" << propertyValue.typeName(); |
652 | return {}; |
653 | } |
654 | QByteArray result; |
655 | handler.serializer(q_ptr, propertyValue, fieldInfo, result); |
656 | |
657 | return result; |
658 | } |
659 | |
660 | bool QProtobufSerializerPrivate::deserializeProperty( |
661 | QProtobufMessage *message, |
662 | const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, |
663 | QProtobufSelfcheckIterator &it) |
664 | { |
665 | Q_ASSERT(it.isValid() && it.bytesLeft() > 0); |
666 | //Each iteration we expect iterator is setup to beginning of next chunk |
667 | int fieldNumber = QtProtobuf::InvalidFieldNumber; |
668 | QtProtobuf::WireTypes wireType = QtProtobuf::WireTypes::Unknown; |
669 | const QProtobufSelfcheckIterator = it; // copy this, we may need it later |
670 | if (!QProtobufSerializerPrivate::decodeHeader(it, fieldIndex&: fieldNumber, wireType)) { |
671 | setDeserializationError( |
672 | error: QAbstractProtobufSerializer::InvalidHeaderError, |
673 | errorString: QCoreApplication::translate(context: "QtProtobuf" , |
674 | key: "Message received doesn't contain valid header byte." )); |
675 | return false; |
676 | } |
677 | |
678 | int index = ordering.indexOfFieldNumber(fieldNumber); |
679 | if (index == -1) { |
680 | // This is an unknown field, it may have been added in a later revision |
681 | // of the Message we are currently deserializing. We must store the |
682 | // bytes for this field and re-emit them later if this message is |
683 | // serialized again. |
684 | qsizetype length = std::distance(first: itBeforeHeader, last: it); // size of header |
685 | length += QProtobufSerializerPrivate::skipSerializedFieldBytes(it, type: wireType); |
686 | |
687 | if (!it.isValid()) { |
688 | setUnexpectedEndOfStreamError(); |
689 | return false; |
690 | } |
691 | |
692 | QProtobufMessagePrivate *messagePrivate = QProtobufMessagePrivate::get(message); |
693 | messagePrivate->storeUnknownEntry(entry: QByteArrayView(itBeforeHeader.data(), length)); |
694 | return true; |
695 | } |
696 | |
697 | QProtobufPropertyOrderingInfo fieldInfo(ordering, index); |
698 | QVariant newPropertyValue = message->property(fieldInfo); |
699 | QMetaType metaType = newPropertyValue.metaType(); |
700 | |
701 | qProtoDebug() << "wireType:" << wireType << "metaType:" << metaType.name() |
702 | << "currentByte:" << QString::number((*it), base: 16); |
703 | |
704 | bool isNonPacked = ordering.getFieldFlags(index) & QtProtobufPrivate::NonPacked; |
705 | auto basicHandler = findIntegratedTypeHandler(metaType, nonPacked: isNonPacked); |
706 | |
707 | if (basicHandler) { |
708 | if (basicHandler->wireType != wireType) { |
709 | // If the handler wiretype mismatches the wiretype received from the |
710 | // wire that most probably means that we received the list in wrong |
711 | // format. This can happen because of mismatch of the field packed |
712 | // option in the protobuf schema on the wire ends. Invert the |
713 | // isNonPacked flag and try to find the handler one more time to make |
714 | // sure that we cover this exceptional case. |
715 | // See the conformance tests |
716 | // Required.Proto3.ProtobufInput.ValidDataRepeated.*.UnpackedInput |
717 | // for details. |
718 | basicHandler = findIntegratedTypeHandler(metaType, nonPacked: !isNonPacked); |
719 | if (!basicHandler || basicHandler->wireType != wireType) { |
720 | setDeserializationError( |
721 | error: QAbstractProtobufSerializer::InvalidHeaderError, |
722 | errorString: QCoreApplication::translate(context: "QtProtobuf" , |
723 | key: "Message received has invalid wiretype for the " |
724 | "field number %1. Expected %2, received %3" ) |
725 | .arg(a: fieldNumber) |
726 | .arg(a: static_cast<int>(basicHandler->wireType)) |
727 | .arg(a: static_cast<int>(wireType))); |
728 | return false; |
729 | } |
730 | } |
731 | |
732 | if (!basicHandler->deserializer(it, newPropertyValue)) { |
733 | setUnexpectedEndOfStreamError(); |
734 | return false; |
735 | } |
736 | } else { |
737 | auto handler = QtProtobufPrivate::findHandler(type: metaType); |
738 | if (!handler.deserializer) { |
739 | qProtoWarning() << "No deserializer for type" << metaType.name(); |
740 | setDeserializationError( |
741 | error: QAbstractProtobufSerializer::NoDeserializerError, |
742 | errorString: QCoreApplication::translate(context: "QtProtobuf" , |
743 | key: "No deserializer is registered for type %1" )); |
744 | return false; |
745 | } |
746 | handler.deserializer(q_ptr, it, newPropertyValue); |
747 | } |
748 | |
749 | return message->setProperty(fieldInfo, value: std::move(newPropertyValue)); |
750 | } |
751 | |
752 | bool QProtobufSerializerPrivate::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) |
753 | { |
754 | int mapIndex = 0; |
755 | QtProtobuf::WireTypes type = QtProtobuf::WireTypes::Unknown; |
756 | auto opt = QProtobufSerializerPrivate::deserializeVarintCommon<QtProtobuf::uint32>(it); |
757 | if (!opt) { |
758 | setUnexpectedEndOfStreamError(); |
759 | return false; |
760 | } |
761 | unsigned int count = opt.value(); |
762 | qProtoDebug("count: %u" , count); |
763 | QProtobufSelfcheckIterator last = it + count; |
764 | while (it.isValid() && it != last) { |
765 | if (!QProtobufSerializerPrivate::decodeHeader(it, fieldIndex&: mapIndex, wireType&: type)) { |
766 | setDeserializationError( |
767 | error: QAbstractProtobufSerializer::InvalidHeaderError, |
768 | errorString: QCoreApplication::translate(context: "QtProtobuf" , |
769 | key: "Message received doesn't contain valid header byte." )); |
770 | return false; |
771 | } |
772 | if (mapIndex == 1) { |
773 | //Only simple types are supported as keys |
774 | QMetaType metaType = key.metaType(); |
775 | auto basicHandler = findIntegratedTypeHandler(metaType, nonPacked: false); |
776 | if (!basicHandler) { |
777 | // clang-format off |
778 | QString errorStr = QCoreApplication::translate(context: "QtProtobuf" , |
779 | key: "Either there is no deserializer for type " |
780 | "%1 or it is not a builtin type" ) |
781 | .arg(a: QLatin1String(key.typeName())); |
782 | // clang-format on |
783 | setDeserializationError(error: QAbstractProtobufSerializer::NoDeserializerError, errorString: errorStr); |
784 | return false; |
785 | } |
786 | basicHandler->deserializer(it, key); |
787 | } else { |
788 | //TODO: replace with some common function |
789 | QMetaType metaType = value.metaType(); |
790 | auto basicHandler = findIntegratedTypeHandler(metaType, nonPacked: false); |
791 | if (basicHandler) { |
792 | basicHandler->deserializer(it, value); |
793 | } else { |
794 | auto handler = QtProtobufPrivate::findHandler(type: metaType); |
795 | if (!handler.deserializer) { |
796 | qProtoWarning() << "No deserializer for type" << value.typeName(); |
797 | setDeserializationError( |
798 | error: QAbstractProtobufSerializer::NoDeserializerError, |
799 | errorString: QCoreApplication::translate(context: "QtProtobuf" , |
800 | key: "No deserializer is registered for type %1" ) |
801 | .arg(a: QLatin1String(value.typeName()))); |
802 | return false; |
803 | } |
804 | handler.deserializer(q_ptr, it, value); |
805 | } |
806 | } |
807 | } |
808 | return it == last; |
809 | } |
810 | |
811 | QAbstractProtobufSerializer::DeserializationError QProtobufSerializer::deserializationError() const |
812 | { |
813 | return d_ptr->deserializationError; |
814 | } |
815 | |
816 | QString QProtobufSerializer::deserializationErrorString() const |
817 | { |
818 | return d_ptr->deserializationErrorString; |
819 | } |
820 | |
821 | void QProtobufSerializerPrivate::setDeserializationError( |
822 | QAbstractProtobufSerializer::DeserializationError error, const QString &errorString) |
823 | { |
824 | deserializationError = error; |
825 | deserializationErrorString = errorString; |
826 | } |
827 | |
828 | QT_END_NAMESPACE |
829 | |