// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2019 Alexey Edelev , Viktor Kopp // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qprotobufserializer.h" #include "qprotobufserializer_p.h" #include "qprotobufregistration.h" #include "qtprotobufdefs_p.h" #include "qtprotobuftypes.h" #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE /*! \class QProtobufSerializer \inmodule QtProtobuf \since 6.5 \brief The QProtobufSerializer class is interface that represents basic functions for serialization/deserialization. The QProtobufSerializer class registers serializers/deserializers for classes implementing a protobuf message, inheriting \l QProtobufMessage. These classes are generated automatically, based on a \c{.proto} file, using the CMake function \l qt_add_protobuf or by running \l {The qtprotobufgen Tool} {qtprotobufgen} directly. */ /*! \fn QProtobufSerializer::DeserializationError QProtobufSerializer::deserializationError() const Returns the last deserialization error. */ /*! \fn QString QProtobufSerializer::deserializationErrorString() const Returns a human-readable string describing the last deserialization error. If there was no error, an empty string is returned. */ using namespace Qt::StringLiterals; using namespace QtProtobufPrivate; template using SerializerRegistryType = std::array; namespace { #define QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(Type, WireType) \ { \ QMetaType::fromType(), \ QProtobufSerializerPrivate::serializeWrapper< \ Type, QProtobufSerializerPrivate::serializeBasic>, \ QProtobufSerializerPrivate::deserializeBasic, \ QProtobufSerializerPrivate::isPresent, WireType \ } #define QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(ListType, Type) \ { \ QMetaType::fromType(), \ QProtobufSerializerPrivate::serializeWrapper< \ ListType, QProtobufSerializerPrivate::serializeListType>, \ QProtobufSerializerPrivate::deserializeList, \ QProtobufSerializerPrivate::isPresent, \ QtProtobuf::WireTypes::LengthDelimited \ } #define QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(ListType, Type, WireType) \ { \ QMetaType::fromType(), \ QProtobufSerializerPrivate::serializeNonPackedWrapper< \ ListType, QProtobufSerializerPrivate::serializeNonPackedList>, \ QProtobufSerializerPrivate::deserializeNonPackedList, \ QProtobufSerializerPrivate::isPresent, WireType \ } constexpr SerializerRegistryType<30> IntegratedTypesSerializers = { { QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(float, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(double, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::int64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::uint64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sint64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed32, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::fixed64, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed32, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::sfixed64, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QtProtobuf::boolean, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QString, QtProtobuf::WireTypes::LengthDelimited), QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(QByteArray, QtProtobuf::WireTypes::LengthDelimited), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int32List, QtProtobuf::int32), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::int64List, QtProtobuf::int64), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint32List, QtProtobuf::uint32), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::uint64List, QtProtobuf::uint64), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint32List, QtProtobuf::sint32), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sint64List, QtProtobuf::sint64), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed32List, QtProtobuf::fixed32), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::fixed64List, QtProtobuf::fixed64), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed32List, QtProtobuf::sfixed32), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::sfixed64List, QtProtobuf::sfixed64), QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(QtProtobuf::boolList, QtProtobuf::boolean), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QStringList, QString, QtProtobuf::WireTypes::LengthDelimited), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QByteArrayList, QByteArray, QtProtobuf::WireTypes::LengthDelimited), } }; constexpr SerializerRegistryType<13> IntegratedNonPackedSerializers = { { QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::floatList, float, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(QtProtobuf::doubleList, double, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::int32List, QtProtobuf::int32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::int64List, QtProtobuf::int64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::uint32List, QtProtobuf::uint32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::uint64List, QtProtobuf::uint64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::sint32List, QtProtobuf::sint32, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::sint64List, QtProtobuf::sint64, QtProtobuf::WireTypes::Varint), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::fixed32List, QtProtobuf::fixed32, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::fixed64List, QtProtobuf::fixed64, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::sfixed32List, QtProtobuf::sfixed32, QtProtobuf::WireTypes::Fixed32), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::sfixed64List, QtProtobuf::sfixed64, QtProtobuf::WireTypes::Fixed64), QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER( QtProtobuf::boolList, QtProtobuf::boolean, QtProtobuf::WireTypes::Varint), } }; template std::optional findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType ®istry) { typename SerializerRegistryType::const_iterator it = std::find_if( registry.begin(), registry.end(), [&metaType](const QProtobufSerializerPrivate::ProtobufSerializationHandler &handler) { return handler.metaType == metaType; }); if (it == registry.end()) return std::nullopt; return { *it }; } std::optional findIntegratedTypeHandler(QMetaType metaType, bool nonPacked) { if (nonPacked) return findIntegratedTypeHandlerImpl(metaType, IntegratedNonPackedSerializers); return findIntegratedTypeHandlerImpl(metaType, IntegratedTypesSerializers); } } /*! Constructs a new serializer instance. */ QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate(this)) { } /*! Destroys the serializer instance. */ QProtobufSerializer::~QProtobufSerializer() = default; QByteArray QProtobufSerializer::serializeMessage(const QProtobufMessage *message) const { d_ptr->clearError(); d_ptr->result = {}; d_ptr->serializeMessage(message); return d_ptr->result; } void QProtobufSerializerPrivate::serializeMessage(const QProtobufMessage *message) { Q_ASSERT(message != nullptr); auto ordering = message->propertyOrdering(); Q_ASSERT(ordering != nullptr); for (int index = 0; index < ordering->fieldCount(); ++index) { int fieldIndex = ordering->getFieldNumber(index); Q_ASSERT_X(fieldIndex <= ProtobufFieldNumMax && fieldIndex >= ProtobufFieldNumMin, "", "fieldIndex is out of range"); QProtobufFieldInfo fieldInfo(*ordering, index); QVariant propertyValue = message->property(fieldInfo); serializeProperty(propertyValue, fieldInfo); } if (preserveUnknownFields) { // Restore any unknown fields we have stored away: const QProtobufMessagePrivate *messagePrivate = QProtobufMessagePrivate::get(message); for (const auto &fields : messagePrivate->unknownEntries) result += fields.join(); } } void QProtobufSerializerPrivate::setUnexpectedEndOfStreamError() { setDeserializationError(QAbstractProtobufSerializer::UnexpectedEndOfStreamError, QCoreApplication::translate("QtProtobuf", "Unexpected end of stream")); } void QProtobufSerializerPrivate::clearError() { deserializationError = QAbstractProtobufSerializer::NoError; deserializationErrorString.clear(); } bool QProtobufSerializer::deserializeMessage(QProtobufMessage *message, QByteArrayView data) const { d_ptr->cachedPropertyValue = QVariant(); d_ptr->cachedIndex = -1; d_ptr->clearError(); d_ptr->it = QProtobufSelfcheckIterator::fromView(data); bool ok = true; while (d_ptr->it.isValid() && d_ptr->it != data.end()) { if (!d_ptr->deserializeProperty(message)) { ok = false; break; } } if (!d_ptr->storeCachedValue(message) || !ok) return false; if (!d_ptr->it.isValid()) d_ptr->setUnexpectedEndOfStreamError(); return d_ptr->it.isValid(); } void QProtobufSerializerPrivate::serializeObject(const QProtobufMessage *message, const QProtobufFieldInfo &fieldInfo) { auto store = result; result = {}; serializeMessage(message); store.append(QProtobufSerializerPrivate::encodeHeader(fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::LengthDelimited)); store.append(QProtobufSerializerPrivate::serializeVarintCommon(result.size())); store.append(result); result = store; } bool QProtobufSerializerPrivate::deserializeObject(QProtobufMessage *message) { if (it.bytesLeft() == 0) { setUnexpectedEndOfStreamError(); return false; } std::optional array = QProtobufSerializerPrivate::deserializeLengthDelimited(it); if (!array) { setUnexpectedEndOfStreamError(); return false; } auto restoreOnReturn = qScopeGuard([prevIt = it, prevCachedPropertyValue = cachedPropertyValue, prevCachedIndex = cachedIndex, this]() { it = prevIt; cachedPropertyValue = prevCachedPropertyValue; cachedIndex = prevCachedIndex; }); cachedPropertyValue.clear(); cachedIndex = -1; QByteArrayView data = *array; clearError(); it = QProtobufSelfcheckIterator::fromView(data); bool ok = true; while (it.isValid() && it != data.end()) { if (!deserializeProperty(message)) { ok = false; break; } } if (!storeCachedValue(message) || !ok) return false; if (!it.isValid()) setUnexpectedEndOfStreamError(); return it.isValid(); } void QProtobufSerializer::serializeObject(const QProtobufMessage *message, const QProtobufFieldInfo &fieldInfo) const { d_ptr->serializeObject(message, fieldInfo); } bool QProtobufSerializer::deserializeObject(QProtobufMessage *message) const { return d_ptr->deserializeObject(message); } void QProtobufSerializerPrivate::serializeEnumList(const QList &value, const QProtobufFieldInfo &fieldInfo) { if (value.isEmpty()) return; auto header = QProtobufSerializerPrivate::encodeHeader(fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::LengthDelimited); if (fieldInfo.getFieldFlags().testFlag(QtProtobufPrivate::NonPacked)) result .append(QProtobufSerializerPrivate::serializeNonPackedList(value, header)); else result.append(header + QProtobufSerializerPrivate::serializeListType(value)); } bool QProtobufSerializerPrivate::deserializeEnumList(QList &value) { QVariant variantValue; if (!QProtobufSerializerPrivate::deserializeList(it, variantValue)) { setUnexpectedEndOfStreamError(); return false; } value = variantValue.value>(); return true; } QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q) { } /*! \internal Encode a property field index and its type into output bytes. Header byte Meaning | Field index | Type ---------- | ------------- | -------- bit number | 7 6 5 4 3 | 2 1 0 fieldIndex: The index of a property in parent object wireType: Serialization type used for the property with index @p fieldIndex Returns a varint-encoded fieldIndex and wireType */ QByteArray QProtobufSerializerPrivate::encodeHeader(int fieldIndex, QtProtobuf::WireTypes wireType) { uint32_t header = (fieldIndex << 3) | int(wireType); return serializeVarintCommon(header); } /*! \internal Decode a property field index and its serialization type from input bytes Iterator: that points to header with encoded field index and serialization type fieldIndex: Decoded index of a property in parent object wireType: Decoded serialization type used for the property with index Return true if both decoded wireType and fieldIndex have "allowed" values and false, otherwise */ bool QProtobufSerializerPrivate::decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex, QtProtobuf::WireTypes &wireType) { if (it.bytesLeft() == 0) return false; auto opt = deserializeVarintCommon(it); if (!opt) return false; uint32_t header = opt.value(); wireType = static_cast(header & 0b00000111); fieldIndex = header >> 3; constexpr int maxFieldIndex = (1 << 29) - 1; return fieldIndex <= maxFieldIndex && fieldIndex > 0 && (wireType == QtProtobuf::WireTypes::Varint || wireType == QtProtobuf::WireTypes::Fixed64 || wireType == QtProtobuf::WireTypes::Fixed32 || wireType == QtProtobuf::WireTypes::LengthDelimited); } void QProtobufSerializerPrivate::skipVarint(QProtobufSelfcheckIterator &it) { while ((*it) & 0x80) ++it; ++it; } void QProtobufSerializerPrivate::skipLengthDelimited(QProtobufSelfcheckIterator &it) { //Get length of length-delimited field auto opt = QProtobufSerializerPrivate::deserializeVarintCommon(it); if (!opt) { it += it.bytesLeft() + 1; return; } QtProtobuf::uint64 length = opt.value(); it += length; } qsizetype QProtobufSerializerPrivate::skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, QtProtobuf::WireTypes type) { const auto *initialIt = QByteArray::const_iterator(it); switch (type) { case QtProtobuf::WireTypes::Varint: skipVarint(it); break; case QtProtobuf::WireTypes::Fixed32: it += sizeof(decltype(QtProtobuf::fixed32::_t)); break; case QtProtobuf::WireTypes::Fixed64: it += sizeof(decltype(QtProtobuf::fixed64::_t)); break; case QtProtobuf::WireTypes::LengthDelimited: skipLengthDelimited(it); break; case QtProtobuf::WireTypes::Unknown: default: Q_UNREACHABLE(); return 0; } return std::distance(initialIt, QByteArray::const_iterator(it)); } void QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue, const QProtobufFieldInfo &fieldInfo) { QMetaType metaType = propertyValue.metaType(); qProtoDebug() << "propertyValue" << propertyValue << "fieldIndex" << fieldInfo.getFieldNumber() << "metaType" << metaType.name(); if (metaType.id() == QMetaType::UnknownType || propertyValue.isNull()) { // Empty value return; } if (metaType.flags() & QMetaType::IsPointer) { auto *messageProperty = propertyValue.value(); auto store = result; result = {}; serializeMessage(messageProperty); store.append(QProtobufSerializerPrivate:: encodeHeader(fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::LengthDelimited)); store.append(QProtobufSerializerPrivate::serializeVarintCommon(result.size())); store.append(result); result = store; return; } const auto fieldFlags = fieldInfo.getFieldFlags(); if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Enum)) { if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Repeated)) { auto value = propertyValue.value>(); serializeEnumList(value, fieldInfo); } else { auto value = propertyValue.value(); if (value == 0 && !isOneofOrOptionalField(fieldInfo)) return; result.append(QProtobufSerializerPrivate::encodeHeader(fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::Varint)); result.append(QProtobufSerializerPrivate::serializeBasic< QtProtobuf::int64>(propertyValue.value())); } return; } auto basicHandler = findIntegratedTypeHandler(metaType, fieldFlags .testFlag(QtProtobufPrivate::NonPacked)); if (basicHandler) { bool serializeUninitialized = isOneofOrOptionalField(fieldInfo); if (!basicHandler->isPresent(propertyValue) && !serializeUninitialized) { return; } QByteArray header = QProtobufSerializerPrivate::encodeHeader(fieldInfo.getFieldNumber(), basicHandler->wireType); result.append(basicHandler->serializer(propertyValue, header)); return; } auto handler = QtProtobufPrivate::findHandler(metaType); if (!handler.serializer) { qProtoWarning() << "No serializer for type" << propertyValue.typeName(); return; } handler.serializer(q_ptr, propertyValue, fieldInfo); } bool QProtobufSerializerPrivate::deserializeProperty(QProtobufMessage *message) { Q_ASSERT(message != nullptr); Q_ASSERT(it.isValid() && it.bytesLeft() > 0); //Each iteration we expect iterator is setup to beginning of next chunk int fieldNumber = QtProtobuf::InvalidFieldNumber; QtProtobuf::WireTypes wireType = QtProtobuf::WireTypes::Unknown; const QProtobufSelfcheckIterator itBeforeHeader = it; // copy this, we may need it later if (!QProtobufSerializerPrivate::decodeHeader(it, fieldNumber, wireType)) { setDeserializationError( QAbstractProtobufSerializer::InvalidHeaderError, QCoreApplication::translate("QtProtobuf", "Message received doesn't contain valid header byte.")); return false; } auto ordering = message->propertyOrdering(); Q_ASSERT(ordering != nullptr); int index = ordering->indexOfFieldNumber(fieldNumber); if (index == -1) { // This is an unknown field, it may have been added in a later revision // of the Message we are currently deserializing. We must store the // bytes for this field and re-emit them later if this message is // serialized again. qsizetype length = std::distance(itBeforeHeader, it); // size of header length += QProtobufSerializerPrivate::skipSerializedFieldBytes(it, wireType); if (!it.isValid()) { setUnexpectedEndOfStreamError(); return false; } if (preserveUnknownFields) { message->detachPrivate(); QProtobufMessagePrivate *messagePrivate = QProtobufMessagePrivate::get(message); messagePrivate->storeUnknownEntry(QByteArrayView(itBeforeHeader.data(), length), fieldNumber); } return true; } QProtobufFieldInfo fieldInfo(*ordering, index); if (cachedIndex != index) { if (!storeCachedValue(message)) return false; cachedPropertyValue = message->property(fieldInfo, true); cachedIndex = index; } QMetaType metaType = cachedPropertyValue.metaType(); qProtoDebug() << "wireType:" << wireType << "metaType:" << metaType.name() << "currentByte:" << QString::number((*it), 16); if (metaType.flags() & QMetaType::IsPointer) { auto *messageProperty = cachedPropertyValue.value(); Q_ASSERT(messageProperty != nullptr); return deserializeObject(messageProperty); } const auto fieldFlags = fieldInfo.getFieldFlags(); if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Enum)) { if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Repeated)) { auto intList = cachedPropertyValue.value>(); if (deserializeEnumList(intList)) { cachedPropertyValue.setValue(intList); return true; } return false; } else { if (deserializeBasic(it, cachedPropertyValue)) return true; return false; } } bool isNonPacked = fieldFlags.testFlag(QtProtobufPrivate::NonPacked); auto basicHandler = findIntegratedTypeHandler(metaType, isNonPacked); if (basicHandler) { if (basicHandler->wireType != wireType) { // If the handler wiretype mismatches the wiretype received from the // wire that most probably means that we received the list in wrong // format. This can happen because of mismatch of the field packed // option in the protobuf schema on the wire ends. Invert the // isNonPacked flag and try to find the handler one more time to make // sure that we cover this exceptional case. // See the conformance tests // Required.Proto3.ProtobufInput.ValidDataRepeated.*.UnpackedInput // for details. basicHandler = findIntegratedTypeHandler(metaType, !isNonPacked); if (!basicHandler || basicHandler->wireType != wireType) { setDeserializationError( QAbstractProtobufSerializer::InvalidHeaderError, QCoreApplication::translate("QtProtobuf", "Message received has invalid wiretype for the " "field number %1. Expected %2, received %3") .arg(fieldNumber) .arg(basicHandler ? static_cast(basicHandler->wireType) : -1) .arg(static_cast(wireType))); return false; } } if (!basicHandler->deserializer(it, cachedPropertyValue)) { setUnexpectedEndOfStreamError(); return false; } } else { auto handler = QtProtobufPrivate::findHandler(metaType); if (!handler.deserializer) { qProtoWarning() << "No deserializer for type" << metaType.name(); QString error = QString::fromUtf8("No deserializer is registered for type %1") .arg(QString::fromUtf8(metaType.name())); setDeserializationError( QAbstractProtobufSerializer::NoDeserializerError, QCoreApplication::translate("QtProtobuf", error.toUtf8().data())); return false; } handler.deserializer(q_ptr, cachedPropertyValue); } return true; } bool QProtobufSerializerPrivate::storeCachedValue(QProtobufMessage *message) { bool ok = true; if (cachedIndex >= 0 && !cachedPropertyValue.isNull()) { const auto *ordering = message->propertyOrdering(); QProtobufFieldInfo fieldInfo(*ordering, cachedIndex); ok = message->setProperty(fieldInfo, cachedPropertyValue); cachedPropertyValue.clear(); cachedIndex = -1; } return ok; } QAbstractProtobufSerializer::DeserializationError QProtobufSerializer::deserializationError() const { return d_ptr->deserializationError; } QString QProtobufSerializer::deserializationErrorString() const { return d_ptr->deserializationErrorString; } void QProtobufSerializerPrivate::setDeserializationError( QAbstractProtobufSerializer::DeserializationError error, const QString &errorString) { deserializationError = error; deserializationErrorString = errorString; } /*! Controls whether the unknown fields received from the wire should be stored in the resulting message or if it should be omitted, based on \a preserveUnknownFields. \since 6.7 */ void QProtobufSerializer::shouldPreserveUnknownFields(bool preserveUnknownFields) { d_ptr->preserveUnknownFields = preserveUnknownFields; } QT_END_NAMESPACE