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
20QT_BEGIN_NAMESPACE
21
22namespace {
23
24/*
25 \internal
26 \brief The HandlersRegistry is a container to store mapping between metatype
27 identifier and serialization handlers.
28*/
29struct 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
47private:
48 QReadWriteLock m_lock;
49 QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry;
50};
51Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry)
52
53inline 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
62void QtProtobufPrivate::registerHandler(QMetaType type,
63 const QtProtobufPrivate::SerializationHandler &handlers)
64{
65 handlersRegistry->registerHandler(type, handlers);
66}
67
68QtProtobufPrivate::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
129using namespace Qt::StringLiterals;
130using namespace QtProtobufPrivate;
131
132template<std::size_t N>
133using SerializerRegistryType =
134 std::array<QProtobufSerializerPrivate::ProtobufSerializationHandler, N>;
135
136namespace {
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{ \
157QMetaType::fromType<ListType>(), \
158 QProtobufSerializerPrivate::serializeNonPackedWrapper< \
159 ListType, QProtobufSerializerPrivate::serializeNonPackedList<Type>>, \
160 QProtobufSerializerPrivate::deserializeNonPackedList<Type>, \
161 QProtobufSerializerPrivate::isPresent<ListType>, WireType \
162}
163
164constexpr 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
220constexpr 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
249template<std::size_t N>
250std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler>
251findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType<N> &registry)
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
263std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler>
264findIntegratedTypeHandler(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*/
276QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate(this))
277{
278}
279
280/*!
281 Destroys the serializer instance.
282*/
283QProtobufSerializer::~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*/
291QByteArray 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
312void QProtobufSerializerPrivate::setUnexpectedEndOfStreamError()
313{
314 setDeserializationError(error: QAbstractProtobufSerializer::UnexpectedEndOfStreamError,
315 errorString: QCoreApplication::translate(context: "QtProtobuf", key: "Unexpected end of stream"));
316}
317
318void 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*/
330bool 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*/
351QByteArray
352QProtobufSerializer::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*/
370bool 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*/
392QByteArray 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*/
407bool 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*/
420QByteArray
421QProtobufSerializer::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*/
444bool 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*/
455QByteArray 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*/
473QByteArray
474QProtobufSerializer::serializeEnumList(const QList<QtProtobuf::int64> &value,
475 const QProtobufPropertyOrderingInfo &fieldInfo) const
476{
477 if (value.isEmpty()) {
478 return {};
479 }
480
481 auto header = 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*/
496bool 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*/
513bool 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
524QProtobufSerializerPrivate::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 */
541QByteArray QProtobufSerializerPrivate::encodeHeader(int fieldIndex,
542 QtProtobuf::WireTypes wireType)
543{
544 uint32_t header = (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 */
557bool QProtobufSerializerPrivate::decodeHeader(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 header = 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
578void QProtobufSerializerPrivate::skipVarint(QProtobufSelfcheckIterator &it)
579{
580 while ((*it) & 0x80)
581 ++it;
582 ++it;
583}
584
585void 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
597qsizetype 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
622QByteArray
623QProtobufSerializerPrivate::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 header = 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
660bool 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 itBeforeHeader = 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
752bool 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
811QAbstractProtobufSerializer::DeserializationError QProtobufSerializer::deserializationError() const
812{
813 return d_ptr->deserializationError;
814}
815
816QString QProtobufSerializer::deserializationErrorString() const
817{
818 return d_ptr->deserializationErrorString;
819}
820
821void QProtobufSerializerPrivate::setDeserializationError(
822 QAbstractProtobufSerializer::DeserializationError error, const QString &errorString)
823{
824 deserializationError = error;
825 deserializationErrorString = errorString;
826}
827
828QT_END_NAMESPACE
829

source code of qtgrpc/src/protobuf/qprotobufserializer.cpp