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 <QtProtobuf/qprotobufserializer.h>
6
7#include <QtProtobuf/private/protobufscalarserializers_p.h>
8#include <QtProtobuf/private/qprotobufmessage_p.h>
9#include <QtProtobuf/private/qprotobufregistration_p.h>
10#include <QtProtobuf/private/qprotobufserializer_p.h>
11#include <QtProtobuf/private/qprotobufserializerbase_p.h>
12#include <QtProtobuf/private/qtprotobufdefs_p.h>
13#include <QtProtobuf/private/qtprotobufserializerhelpers_p.h>
14#include <QtProtobuf/qprotobufmessage.h>
15#include <QtProtobuf/qtprotobuftypes.h>
16
17#include <QtCore/qcoreapplication.h>
18#include <QtCore/qlist.h>
19#include <QtCore/qmetaobject.h>
20#include <QtCore/qmetatype.h>
21#include <QtCore/qreadwritelock.h>
22
23QT_BEGIN_NAMESPACE
24
25/*!
26 \class QProtobufSerializer
27 \inmodule QtProtobuf
28 \since 6.5
29 \brief The QProtobufSerializer class is interface that represents
30 basic functions for serialization/deserialization.
31
32 The QProtobufSerializer class registers serializers/deserializers for
33 classes implementing a protobuf message, inheriting \l QProtobufMessage. These
34 classes are generated automatically, based on a \c{.proto} file, using the CMake
35 function \l qt_add_protobuf or by running
36 \l {The qtprotobufgen Tool} {qtprotobufgen} directly.
37*/
38
39using namespace Qt::StringLiterals;
40using namespace QtProtobufPrivate;
41using namespace ProtobufScalarSerializers;
42
43template<std::size_t N>
44using SerializerRegistryType =
45 std::array<QProtobufSerializerPrivate::ProtobufSerializationHandler, N>;
46
47namespace {
48
49#define QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(Type, WireType) \
50 { QMetaType::fromType<Type>(), \
51 QProtobufSerializerPrivate::serializeWrapper<Type, serializeBasic<Type>>, \
52 deserializeBasic<Type>, ProtobufFieldPresenceChecker::isPresent<Type>, WireType }
53#define QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(ListType, Type) \
54 { QMetaType::fromType<ListType>(), \
55 QProtobufSerializerPrivate::serializeWrapper<ListType, serializeListType<Type>>, \
56 deserializeList<Type>, ProtobufFieldPresenceChecker::isPresent<ListType>, \
57 QtProtobuf::WireTypes::LengthDelimited }
58
59#define QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(ListType, Type, WireType) \
60 { QMetaType::fromType<ListType>(), \
61 QProtobufSerializerPrivate::serializeNonPackedWrapper<ListType, \
62 serializeNonPackedList<Type>>, \
63 deserializeNonPackedList<Type>, ProtobufFieldPresenceChecker::isPresent<ListType>, \
64 WireType }
65
66constexpr SerializerRegistryType<30> IntegratedTypesSerializers = { ._M_elems: {
67 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(float, QtProtobuf::WireTypes::Fixed32),
68 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(double, QtProtobuf::WireTypes::Fixed64),
69 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int32,
70 QtProtobuf::WireTypes::Varint),
71 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int64,
72 QtProtobuf::WireTypes::Varint),
73 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint32,
74 QtProtobuf::WireTypes::Varint),
75 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint64,
76 QtProtobuf::WireTypes::Varint),
77 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint32,
78 QtProtobuf::WireTypes::Varint),
79 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint64,
80 QtProtobuf::WireTypes::Varint),
81 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed32,
82 QtProtobuf::WireTypes::Fixed32),
83 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed64,
84 QtProtobuf::WireTypes::Fixed64),
85 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed32,
86 QtProtobuf::WireTypes::Fixed32),
87 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed64,
88 QtProtobuf::WireTypes::Fixed64),
89 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::boolean,
90 QtProtobuf::WireTypes::Varint),
91 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QString,
92 QtProtobuf::WireTypes::LengthDelimited),
93 QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QByteArray,
94 QtProtobuf::WireTypes::LengthDelimited),
95 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float),
96 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double),
97 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int32List, QtProtobuf::int32),
98 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int64List, QtProtobuf::int64),
99 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint32List,
100 QtProtobuf::uint32),
101 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint64List,
102 QtProtobuf::uint64),
103 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint32List,
104 QtProtobuf::sint32),
105 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint64List,
106 QtProtobuf::sint64),
107 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed32List,
108 QtProtobuf::fixed32),
109 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed64List,
110 QtProtobuf::fixed64),
111 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed32List,
112 QtProtobuf::sfixed32),
113 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed64List,
114 QtProtobuf::sfixed64),
115 QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::boolList, QtProtobuf::boolean),
116 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
117 QStringList, QString, QtProtobuf::WireTypes::LengthDelimited),
118 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
119 QByteArrayList, QByteArray, QtProtobuf::WireTypes::LengthDelimited),
120} };
121
122constexpr SerializerRegistryType<13> IntegratedNonPackedSerializers = { ._M_elems: {
123 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float,
124 QtProtobuf::WireTypes::Fixed32),
125 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double,
126 QtProtobuf::WireTypes::Fixed64),
127 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
128 QtProtobuf::int32List, QtProtobuf::int32, QtProtobuf::WireTypes::Varint),
129 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
130 QtProtobuf::int64List, QtProtobuf::int64, QtProtobuf::WireTypes::Varint),
131 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
132 QtProtobuf::uint32List, QtProtobuf::uint32, QtProtobuf::WireTypes::Varint),
133 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
134 QtProtobuf::uint64List, QtProtobuf::uint64, QtProtobuf::WireTypes::Varint),
135 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
136 QtProtobuf::sint32List, QtProtobuf::sint32, QtProtobuf::WireTypes::Varint),
137 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
138 QtProtobuf::sint64List, QtProtobuf::sint64, QtProtobuf::WireTypes::Varint),
139 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
140 QtProtobuf::fixed32List, QtProtobuf::fixed32, QtProtobuf::WireTypes::Fixed32),
141 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
142 QtProtobuf::fixed64List, QtProtobuf::fixed64, QtProtobuf::WireTypes::Fixed64),
143 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
144 QtProtobuf::sfixed32List, QtProtobuf::sfixed32, QtProtobuf::WireTypes::Fixed32),
145 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
146 QtProtobuf::sfixed64List, QtProtobuf::sfixed64, QtProtobuf::WireTypes::Fixed64),
147 QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(
148 QtProtobuf::boolList, QtProtobuf::boolean, QtProtobuf::WireTypes::Varint),
149} };
150
151template<std::size_t N>
152std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler>
153findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType<N> &registry)
154{
155 typename SerializerRegistryType<N>::const_iterator it = std::find_if(
156 registry.begin(), registry.end(),
157 [&metaType](const QProtobufSerializerPrivate::ProtobufSerializationHandler &handler) {
158 return handler.metaType == metaType;
159 });
160 if (it == registry.end())
161 return std::nullopt;
162 return { *it };
163}
164
165std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler>
166findIntegratedTypeHandler(QMetaType metaType, bool nonPacked)
167{
168 if (nonPacked)
169 return findIntegratedTypeHandlerImpl(metaType, registry: IntegratedNonPackedSerializers);
170
171 return findIntegratedTypeHandlerImpl(metaType, registry: IntegratedTypesSerializers);
172}
173} // namespace
174
175QProtobufSerializerImpl::QProtobufSerializerImpl(QProtobufSerializerPrivate *parent) : m_parent(parent)
176{
177
178}
179
180QProtobufSerializerImpl::~QProtobufSerializerImpl() = default;
181
182void QProtobufSerializerImpl::reset()
183{
184 m_state.clear();
185 m_result = {};
186}
187
188void QProtobufSerializerImpl::serializeUnknownFields(const QProtobufMessage *message)
189{
190 if (m_parent->preserveUnknownFields) {
191 // Restore any unknown fields we have stored away:
192 for (const auto &fields :
193 std::as_const(t: QProtobufMessagePrivate::get(message)->unknownEntries)) {
194 m_result += fields.join();
195 }
196 }
197}
198
199bool QProtobufSerializerImpl::serializeEnum(QVariant &value,
200 const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo)
201{
202 const auto fieldFlags = fieldInfo.fieldFlags();
203 if (fieldFlags.testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) {
204 if (!value.canConvert<QList<QtProtobuf::int64>>())
205 return false;
206 QList<QtProtobuf::int64> listValue = value.value<QList<QtProtobuf::int64>>();
207 if (listValue.isEmpty())
208 return true;
209
210 if (fieldFlags.testFlag(flag: QtProtobufPrivate::FieldFlag::NonPacked)) {
211 const auto header = encodeHeader(fieldIndex: fieldInfo.fieldNumber(),
212 wireType: QtProtobuf::WireTypes::Varint);
213 m_result.append(a: serializeNonPackedList<QtProtobuf::int64>(listValue, header));
214 } else {
215 m_result.append(a: encodeHeader(fieldIndex: fieldInfo.fieldNumber(),
216 wireType: QtProtobuf::WireTypes::LengthDelimited));
217 m_result.append(a: serializeListType<QtProtobuf::int64>(listValue));
218 }
219 } else {
220 if (!value.canConvert<QtProtobuf::int64>())
221 return false;
222
223 if (!ProtobufFieldPresenceChecker::isPresent<QtProtobuf::int64>(value)
224 && !isOneofOrOptionalField(flags: fieldInfo.fieldFlags())) {
225 return true;
226 }
227
228 m_result.append(a: encodeHeader(fieldIndex: fieldInfo.fieldNumber(), wireType: QtProtobuf::WireTypes::Varint));
229 m_result.append(a: serializeBasic<QtProtobuf::int64>(value: value.value<QtProtobuf::int64>()));
230 }
231 return true;
232}
233
234bool QProtobufSerializerImpl::serializeScalarField(const QVariant &value,
235 const QProtobufFieldInfo &fieldInfo)
236{
237 const QtProtobufPrivate::FieldFlags flags = fieldInfo.fieldFlags();
238 const bool isPacked = flags.testFlag(flag: QtProtobufPrivate::FieldFlag::NonPacked);
239 auto basicHandler = findIntegratedTypeHandler(metaType: value.metaType(), nonPacked: isPacked);
240 // Is not a protobuf scalar value type
241 if (!basicHandler)
242 return false;
243
244 // Field is empty
245 if (!basicHandler->isPresent(value) && !isOneofOrOptionalField(flags))
246 return true;
247
248 const QByteArray header = encodeHeader(fieldIndex: fieldInfo.fieldNumber(), wireType: basicHandler->wireType);
249 m_result.append(a: basicHandler->serializer(value, header));
250 return true;
251}
252
253void QProtobufSerializerImpl::serializeMessageFieldBegin()
254{
255 m_state.emplaceBack(args: std::move(m_result));
256 m_result = {};
257}
258
259void QProtobufSerializerImpl::serializeMessageFieldEnd(const QProtobufMessage *message,
260 const QProtobufFieldInfo &fieldInfo)
261{
262 Q_ASSERT(!m_state.isEmpty());
263
264 serializeUnknownFields(message);
265
266 QByteArray last = m_state.takeLast();
267 last.append(a: encodeHeader(fieldIndex: fieldInfo.fieldNumber(), wireType: QtProtobuf::WireTypes::LengthDelimited));
268 last.append(a: serializeVarintCommon<uint32_t>(value: m_result.size()));
269 last.append(a: m_result);
270 m_result = last;
271}
272
273QByteArray QProtobufSerializerImpl::encodeHeader(int fieldIndex, QtProtobuf::WireTypes wireType)
274{
275 // Encodes a property field index and its type into output bytes.
276
277 // Header byte
278 // Meaning | Field index | Type
279 // ---------- | ------------- | --------
280 // bit number | 7 6 5 4 3 | 2 1 0
281
282 // fieldIndex: The index of a property in parent object
283 // wireType: Serialization type used for the property with fieldIndex
284
285 // Returns a varint-encoded fieldIndex and wireType
286
287 uint32_t header = (fieldIndex << 3) | int(wireType);
288 return serializeVarintCommon<uint32_t>(value: header);
289}
290
291QProtobufDeserializerImpl::QProtobufDeserializerImpl(QProtobufSerializerPrivate *parent)
292 : m_parent(parent)
293{
294}
295
296QProtobufDeserializerImpl::~QProtobufDeserializerImpl()
297 = default;
298
299void QProtobufDeserializerImpl::reset(QByteArrayView data)
300{
301 m_it = QProtobufSelfcheckIterator::fromView(container: data);
302 m_state.push_back(t: data.end());
303 clearCachedValue();
304}
305
306void QProtobufDeserializerImpl::setError(QAbstractProtobufSerializer::Error error,
307 QAnyStringView errorString)
308{
309 m_parent->lastError = error;
310 m_parent->lastErrorString = errorString.toString();
311}
312
313bool QProtobufDeserializerImpl::deserializeEnum(QVariant &value,
314 const QProtobufFieldInfo &fieldInfo)
315{
316 const auto fieldFlags = fieldInfo.fieldFlags();
317 if (fieldFlags.testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) {
318 QMetaType metaType = value.metaType();
319 value.convert(type: QMetaType::fromType<QList<QtProtobuf::int64>>());
320 bool result = false;
321 if (m_wireType == QtProtobuf::WireTypes::Varint) {
322 result = deserializeNonPackedList<QtProtobuf::int64>(it&: m_it, previousValue&: value);
323 } else if (m_wireType == QtProtobuf::WireTypes::LengthDelimited) {
324 result = deserializeList<QtProtobuf::int64>(it&: m_it, previousValue&: value);
325 }
326 value.convert(type: metaType);
327 return result;
328 }
329
330 return deserializeBasic<QtProtobuf::int64>(it&: m_it, variantValue&: value);
331}
332
333int QProtobufDeserializerImpl::nextFieldIndex(QProtobufMessage *message)
334{
335 Q_ASSERT(message);
336
337 const auto *ordering = message->propertyOrdering();
338 Q_ASSERT(ordering != nullptr);
339
340 while (m_it.isValid() && m_it != m_state.last()) {
341 // Each iteration we expect iterator is setup to beginning of next chunk
342 int fieldNumber = QtProtobuf::InvalidFieldNumber;
343 const QProtobufSelfcheckIterator fieldBegin = m_it; // copy this, we may need it later
344 if (!decodeHeader(it&: m_it, fieldIndex&: fieldNumber, wireType&: m_wireType)) {
345 setError(error: QAbstractProtobufSerializer::Error::InvalidHeader,
346 errorString: "Message received doesn't contain valid header byte.");
347 return -1;
348 }
349
350 int index = ordering->indexOfFieldNumber(fieldNumber);
351 if (index == -1) {
352 // This is an unknown field, it may have been added in a later revision
353 // of the Message we are currently deserializing. We must store the
354 // bytes for this field and re-emit them later if this message is
355 // serialized again.
356 if (auto length = skipField(fieldBegin); length < 0) {
357 return -1;
358 } else if (length > 0 && m_parent->preserveUnknownFields) {
359 QByteArrayView fieldData(fieldBegin.data(), length);
360 QProtobufMessagePrivate::storeUnknownEntry(message, entry: fieldData, fieldNumber);
361 }
362 continue;
363 }
364
365 if (ordering->fieldFlags(index).testAnyFlags(flags: { QtProtobufPrivate::FieldFlag::Message,
366 QtProtobufPrivate::FieldFlag::Map })) {
367 auto opt = deserializeVarintCommon<QtProtobuf::uint64>(it&: m_it);
368 if (!opt) {
369 setUnexpectedEndOfStreamError();
370 return -1;
371 }
372
373 quint64 length = *opt;
374 if (!m_it.isValid() || quint64(m_it.bytesLeft()) < length
375 || length > quint64(QByteArray::maxSize())) {
376 setUnexpectedEndOfStreamError();
377 return -1;
378 }
379
380 m_state.push_back(t: m_it.data() + length);
381 }
382 return index;
383 }
384
385 if (!m_it.isValid())
386 setUnexpectedEndOfStreamError();
387
388 m_state.pop_back();
389 return -1;
390}
391
392bool QProtobufDeserializerImpl::deserializeScalarField(QVariant &value,
393 const QtProtobufPrivate::QProtobufFieldInfo
394 &fieldInfo)
395{
396 QMetaType metaType = value.metaType();
397
398 // All repeated scalar types should have LenghtDelimited wiretype.
399 // If the wiretype received from the wire is not LenghtDelimited,
400 // that most probably means that we received the list in wrong
401 // format. This can happen because of mismatch of the field packed
402 // option in the protobuf schema on the wire ends.
403 // look for non-packed list in this case. Otherwise it's the regular
404 // packed repeated field.
405 // See the conformance tests
406 // Required.Proto3.ProtobufInput.ValidDataRepeated.*.UnpackedInput
407 // for details.
408 bool isNonPacked = m_wireType != QtProtobuf::WireTypes::LengthDelimited &&
409 fieldInfo.fieldFlags().testFlags(flags: FieldFlag::Repeated);
410
411 auto basicHandler = findIntegratedTypeHandler(metaType, nonPacked: isNonPacked);
412 if (!basicHandler)
413 return false;
414
415 if (basicHandler->wireType != m_wireType) {
416 setError(error: QAbstractProtobufSerializer::Error::InvalidHeader,
417 errorString: QCoreApplication::translate(context: "QtProtobuf",
418 key: "Invalid wiretype for the %1 "
419 "field number %1. Expected %2, received %3")
420 .arg(a: QString::fromUtf8(utf8: metaType.name()))
421 .arg(a: fieldInfo.fieldNumber())
422 .arg(a: basicHandler ? static_cast<int>(basicHandler->wireType) : -1)
423 .arg(a: static_cast<int>(m_wireType)));
424 value.clear();
425 } else if (!basicHandler->deserializer(m_it, value)) {
426 value.clear();
427 setUnexpectedEndOfStreamError();
428 }
429
430 return true;
431}
432
433qsizetype QProtobufDeserializerImpl::skipField(const QProtobufSelfcheckIterator &fieldBegin)
434{
435 switch (m_wireType) {
436 case QtProtobuf::WireTypes::Varint:
437 skipVarint();
438 break;
439 case QtProtobuf::WireTypes::Fixed32:
440 m_it += sizeof(decltype(QtProtobuf::fixed32::t));
441 break;
442 case QtProtobuf::WireTypes::Fixed64:
443 m_it += sizeof(decltype(QtProtobuf::fixed64::t));
444 break;
445 case QtProtobuf::WireTypes::LengthDelimited:
446 skipLengthDelimited();
447 break;
448 case QtProtobuf::WireTypes::Unknown:
449 default:
450 Q_UNREACHABLE();
451 return 0;
452 }
453
454 if (!m_it.isValid()) {
455 setUnexpectedEndOfStreamError();
456 return -1;
457 }
458
459 return std::distance(first: fieldBegin, last: m_it);
460}
461
462void QProtobufDeserializerImpl::skipVarint()
463{
464 while ((*m_it) & 0x80)
465 ++m_it;
466 ++m_it;
467}
468
469void QProtobufDeserializerImpl::skipLengthDelimited()
470{
471 //Get length of length-delimited field
472 auto opt = deserializeVarintCommon<QtProtobuf::uint64>(it&: m_it);
473 if (!opt) {
474 m_it += m_it.bytesLeft() + 1;
475 return;
476 }
477 QtProtobuf::uint64 length = opt.value();
478 m_it += length;
479}
480
481void QProtobufDeserializerImpl::setUnexpectedEndOfStreamError()
482{
483 setError(error: QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
484 errorString: QCoreApplication::translate(context: "QtProtobuf", key: "Unexpected end of stream"));
485}
486
487bool QProtobufDeserializerImpl::decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex,
488 QtProtobuf::WireTypes &wireType)
489{
490 if (it.bytesLeft() == 0)
491 return false;
492 auto opt = deserializeVarintCommon<uint32_t>(it);
493 if (!opt)
494 return false;
495 uint32_t header = opt.value();
496 wireType = static_cast<QtProtobuf::WireTypes>(header & 0b00000111);
497 fieldIndex = header >> 3;
498
499 constexpr int maxFieldIndex = (1 << 29) - 1;
500 return fieldIndex <= maxFieldIndex && fieldIndex > 0
501 && (wireType == QtProtobuf::WireTypes::Varint || wireType == QtProtobuf::WireTypes::Fixed64
502 || wireType == QtProtobuf::WireTypes::Fixed32
503 || wireType == QtProtobuf::WireTypes::LengthDelimited);
504}
505
506QProtobufSerializerPrivate::QProtobufSerializerPrivate() : serializer(this), deserializer(this)
507{
508}
509
510void QProtobufSerializerPrivate::clearError()
511{
512 lastError = QAbstractProtobufSerializer::Error::None;
513 lastErrorString.clear();
514}
515
516/*!
517 Constructs a new serializer instance.
518*/
519QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate())
520{
521}
522
523/*!
524 Destroys the serializer instance.
525*/
526QProtobufSerializer::~QProtobufSerializer() = default;
527
528QByteArray QProtobufSerializer::serializeMessage(const QProtobufMessage *message) const
529{
530 d_ptr->clearError();
531 d_ptr->serializer.reset();
532 d_ptr->serializer.serializeMessage(message);
533 d_ptr->serializer.serializeUnknownFields(message);
534 auto result = d_ptr->serializer.result();
535 d_ptr->serializer.reset();
536 return result;
537}
538
539bool QProtobufSerializer::deserializeMessage(QProtobufMessage *message, QByteArrayView data) const
540{
541 d_ptr->clearError();
542 d_ptr->deserializer.reset(data);
543 d_ptr->deserializer.deserializeMessage(message);
544 d_ptr->deserializer.reset(data: {});
545 return d_ptr->lastError == QAbstractProtobufSerializer::Error::None;
546}
547
548/*!
549 Returns the last deserialization error for the serializer instance.
550 \sa lastErrorString()
551*/
552QAbstractProtobufSerializer::Error QProtobufSerializer::lastError() const
553{
554 return d_ptr->lastError;
555}
556
557/*!
558 Returns the last deserialization error string for the serializer instance.
559 \sa lastError()
560*/
561QString QProtobufSerializer::lastErrorString() const
562{
563 return d_ptr->lastErrorString;
564}
565
566/*!
567 Controls whether the unknown fields received from the wire should be
568 stored in the resulting message or if it should be omitted, based
569 on \a preserveUnknownFields.
570 \since 6.7
571*/
572void QProtobufSerializer::shouldPreserveUnknownFields(bool preserveUnknownFields)
573{
574 d_ptr->preserveUnknownFields = preserveUnknownFields;
575}
576
577QT_END_NAMESPACE
578

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