qtgrpc/src/protobuf/qprotobufserializer.cpp

705 lines
30 KiB
C++

// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>, Viktor Kopp <vifactor@gmail.com>
// 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 <QtCore/qmetatype.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qvariant.h>
#include <QtCore/qreadwritelock.h>
#include <QtProtobuf/qprotobufmessage.h>
#include <QtProtobuf/private/qprotobufserializer_p.h>
#include <QtProtobuf/private/qprotobufmessage_p.h>
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<std::size_t N>
using SerializerRegistryType =
std::array<QProtobufSerializerPrivate::ProtobufSerializationHandler, N>;
namespace {
#define QT_CONSTRUCT_PROTOBUF_SERIALIZATION_HANDLER(Type, WireType) \
{ \
QMetaType::fromType<Type>(), \
QProtobufSerializerPrivate::serializeWrapper< \
Type, QProtobufSerializerPrivate::serializeBasic<Type>>, \
QProtobufSerializerPrivate::deserializeBasic<Type>, \
QProtobufSerializerPrivate::isPresent<Type>, WireType \
}
#define QT_CONSTRUCT_PROTOBUF_LIST_SERIALIZATION_HANDLER(ListType, Type) \
{ \
QMetaType::fromType<ListType>(), \
QProtobufSerializerPrivate::serializeWrapper< \
ListType, QProtobufSerializerPrivate::serializeListType<Type>>, \
QProtobufSerializerPrivate::deserializeList<Type>, \
QProtobufSerializerPrivate::isPresent<ListType>, \
QtProtobuf::WireTypes::LengthDelimited \
}
#define QT_CONSTRUCT_PROTOBUF_NON_PACKED_LIST_SERIALIZATION_HANDLER(ListType, Type, WireType) \
{ \
QMetaType::fromType<ListType>(), \
QProtobufSerializerPrivate::serializeNonPackedWrapper< \
ListType, QProtobufSerializerPrivate::serializeNonPackedList<Type>>, \
QProtobufSerializerPrivate::deserializeNonPackedList<Type>, \
QProtobufSerializerPrivate::isPresent<ListType>, 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::size_t N>
std::optional<QProtobufSerializerPrivate::ProtobufSerializationHandler>
findIntegratedTypeHandlerImpl(QMetaType metaType, const SerializerRegistryType<N> &registry)
{
typename SerializerRegistryType<N>::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<QProtobufSerializerPrivate::ProtobufSerializationHandler>
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<uint32_t>(result.size()));
store.append(result);
result = store;
}
bool QProtobufSerializerPrivate::deserializeObject(QProtobufMessage *message)
{
if (it.bytesLeft() == 0) {
setUnexpectedEndOfStreamError();
return false;
}
std::optional<QByteArray>
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<QtProtobuf::int64> &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<QtProtobuf::int64>(value,
header));
else
result.append(header
+ QProtobufSerializerPrivate::serializeListType<QtProtobuf::int64>(value));
}
bool QProtobufSerializerPrivate::deserializeEnumList(QList<QtProtobuf::int64> &value)
{
QVariant variantValue;
if (!QProtobufSerializerPrivate::deserializeList<QtProtobuf::int64>(it, variantValue)) {
setUnexpectedEndOfStreamError();
return false;
}
value = variantValue.value<QList<QtProtobuf::int64>>();
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<uint32_t>(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<uint32_t>(it);
if (!opt)
return false;
uint32_t header = opt.value();
wireType = static_cast<QtProtobuf::WireTypes>(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<QtProtobuf::uint64>(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<QProtobufMessage *>();
auto store = result;
result = {};
serializeMessage(messageProperty);
store.append(QProtobufSerializerPrivate::
encodeHeader(fieldInfo.getFieldNumber(),
QtProtobuf::WireTypes::LengthDelimited));
store.append(QProtobufSerializerPrivate::serializeVarintCommon<uint32_t>(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<QList<QtProtobuf::int64>>();
serializeEnumList(value, fieldInfo);
} else {
auto value = propertyValue.value<int64_t>();
if (value == 0 && !isOneofOrOptionalField(fieldInfo))
return;
result.append(QProtobufSerializerPrivate::encodeHeader(fieldInfo.getFieldNumber(),
QtProtobuf::WireTypes::Varint));
result.append(QProtobufSerializerPrivate::serializeBasic<
QtProtobuf::int64>(propertyValue.value<int64_t>()));
}
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<QProtobufMessage *>();
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<QList<QtProtobuf::int64>>();
if (deserializeEnumList(intList)) {
cachedPropertyValue.setValue(intList);
return true;
}
return false;
} else {
if (deserializeBasic<QtProtobuf::int64>(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<int>(basicHandler->wireType) : -1)
.arg(static_cast<int>(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