Generalize deserializer in protobuf and JSON serializers

Move the generic logic of serializer to a separate class and
use this class to implement the protobuf and JSON deserialization.

This also fixed one of the conformance usecases since related
to invalid enum handling.

Pick-to: 6.8 6.9
Task-number: QTBUG-128812
Fixes: QTBUG-112423
Fixes: QTBUG-112425
Fixes: QTBUG-112424
Change-Id: I400303a8666df90050a54bd7036daa0107adcce5
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
This commit is contained in:
Alexey Edelev 2024-09-27 12:55:53 +02:00
parent 27b618fcc4
commit 3df9d285da
8 changed files with 680 additions and 610 deletions

View File

@ -6,6 +6,7 @@ qt_internal_add_module(Protobuf
protobuffieldpresencechecker_p.h protobuffieldpresencechecker_p.h
qtprotobufglobal.h qtprotobufglobal.h
qabstractprotobufserializer.cpp qabstractprotobufserializer.h qabstractprotobufserializer.cpp qabstractprotobufserializer.h
qprotobufdeserializerbase_p.h qprotobufdeserializerbase.cpp
qprotobufjsonserializer.cpp qprotobufjsonserializer.h qprotobufjsonserializer.cpp qprotobufjsonserializer.h
qprotobuflazymessagepointer.h qprotobuflazymessagepointer.h
qprotobufmessage.cpp qprotobufmessage.h qprotobufmessage_p.h qprotobufmessage.cpp qprotobufmessage.h qprotobufmessage_p.h

View File

@ -0,0 +1,136 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtProtobuf/private/qprotobufdeserializerbase_p.h>
#include <QtProtobuf/private/qprotobufregistration_p.h>
#include <QtProtobuf/private/qtprotobuflogging_p.h>
#include <QtProtobuf/private/qtprotobufserializerhelpers_p.h>
QT_BEGIN_NAMESPACE
QProtobufDeserializerBase::QProtobufDeserializerBase()
= default;
QProtobufDeserializerBase::~QProtobufDeserializerBase()
= default;
bool QProtobufDeserializerBase::deserializeMessageField(QProtobufMessage *message)
{
Q_ASSERT(message != nullptr);
auto prevCachedRepeatedIterator = std::move(m_cachedRepeatedIterator);
auto prevCachedPropertyValue = m_cachedPropertyValue;
auto prevCachedIndex = m_cachedIndex;
clearCachedValue();
bool result = deserializeMessage(message);
m_cachedPropertyValue = prevCachedPropertyValue;
m_cachedIndex = prevCachedIndex;
m_cachedRepeatedIterator = std::move(prevCachedRepeatedIterator);
return result;
}
bool QProtobufDeserializerBase::deserializeMessage(QProtobufMessage *message)
{
Q_ASSERT(message != nullptr);
const auto *ordering = message->propertyOrdering();
for (int fieldIndex = nextFieldIndex(message); fieldIndex >= 0;
fieldIndex = nextFieldIndex(message)) {
QtProtobufPrivate::QProtobufFieldInfo fieldInfo(*ordering, fieldIndex);
if (m_cachedIndex != fieldIndex) {
if (!storeCachedValue(message)) {
setError(QAbstractProtobufSerializer::Error::InvalidFormat,
"Unable to store the property in message");
return false;
}
m_cachedPropertyValue = QtProtobufSerializerHelpers::messageProperty(message, fieldInfo,
true);
m_cachedIndex = fieldIndex;
}
QMetaType metaType = m_cachedPropertyValue.metaType();
if (metaType.flags().testFlag(QMetaType::IsPointer)) {
if (!deserializeMessageField(m_cachedPropertyValue.value<QProtobufMessage *>()))
return false;
continue;
}
const auto fieldFlags = fieldInfo.fieldFlags();
if ((fieldFlags.testFlags(RepeatedMessageFlags)
|| fieldFlags.testFlags({ QtProtobufPrivate::FieldFlag::Map }))
&& m_cachedPropertyValue.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
if (!m_cachedRepeatedIterator.isValid())
m_cachedRepeatedIterator = m_cachedPropertyValue.view<QProtobufRepeatedIterator>();
if (!deserializeMessageField(m_cachedRepeatedIterator.addNext()))
return false;
m_cachedRepeatedIterator.push();
continue;
}
if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Enum)) {
if (!deserializeEnum(m_cachedPropertyValue, fieldInfo)) {
setError(QAbstractProtobufSerializer::Error::UnknownType,
"Unable to covert enum field to compatible serialization format");
return false;
}
continue;
}
if (deserializeScalarField(m_cachedPropertyValue, fieldInfo)) {
if (!m_cachedPropertyValue.isValid())
return false;
continue;
}
auto handler = QtProtobufPrivate::findHandler(metaType);
if (!handler.deserializer) {
qProtoWarning() << "No deserializer for type" << metaType.name();
setError(QAbstractProtobufSerializer::Error::UnknownType,
QString::fromUtf8("No deserializer is registered for type %1")
.arg(QString::fromUtf8(metaType.name())));
return false;
}
handler.deserializer([this](QProtobufMessage *
message) { return this->deserializeMessageField(message); },
m_cachedPropertyValue.data());
}
if (!storeCachedValue(message)) {
setError(QAbstractProtobufSerializer::Error::InvalidFormat,
"Unable to store the property in message");
return false;
}
return true;
}
bool QProtobufDeserializerBase::storeCachedValue(QProtobufMessage *message)
{
bool ok = true;
if (m_cachedIndex >= 0 && !m_cachedPropertyValue.isNull()) {
const auto *ordering = message->propertyOrdering();
QtProtobufPrivate::QProtobufFieldInfo fieldInfo(*ordering, m_cachedIndex);
ok = QtProtobufSerializerHelpers::setMessageProperty(message, fieldInfo,
m_cachedPropertyValue);
clearCachedValue();
}
return ok;
}
void QProtobufDeserializerBase::clearCachedValue()
{
m_cachedPropertyValue.clear();
m_cachedIndex = -1;
m_cachedRepeatedIterator = {};
}
QT_END_NAMESPACE

View File

@ -0,0 +1,65 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPROTOBUFDESERIALIZERBASE_P_H
#define QPROTOBUFDESERIALIZERBASE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtProtobuf/qabstractprotobufserializer.h>
#include <QtProtobuf/qprotobufpropertyordering.h>
#include <QtProtobuf/qprotobufrepeatediterator.h>
#include <QtCore/qtconfigmacros.h>
QT_BEGIN_NAMESPACE
class QVariant;
class QProtobufMessage;
class QProtobufDeserializerBase
{
public:
QProtobufDeserializerBase();
bool deserializeMessage(QProtobufMessage *message);
void clearCachedValue();
protected:
~QProtobufDeserializerBase();
virtual void setError(QAbstractProtobufSerializer::Error error, QAnyStringView errorString) = 0;
private:
virtual bool deserializeEnum(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) = 0;
virtual int nextFieldIndex(QProtobufMessage *message) = 0;
virtual bool deserializeScalarField(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) = 0;
bool deserializeMessageField(QProtobufMessage *message);
bool storeCachedValue(QProtobufMessage *message);
QVariant m_cachedPropertyValue;
QProtobufRepeatedIterator m_cachedRepeatedIterator;
int m_cachedIndex = -1;
Q_DISABLE_COPY_MOVE(QProtobufDeserializerBase)
public:
static constexpr QtProtobufPrivate::FieldFlags RepeatedMessageFlags{
QtProtobufPrivate::FieldFlag::Message, QtProtobufPrivate::FieldFlag::Repeated
};
};
QT_END_NAMESPACE
#endif // QPROTOBUFDESERIALIZERBASE_P_H

View File

@ -4,6 +4,7 @@
#include <QtProtobuf/qprotobufjsonserializer.h> #include <QtProtobuf/qprotobufjsonserializer.h>
#include <QtProtobuf/private/protobuffieldpresencechecker_p.h> #include <QtProtobuf/private/protobuffieldpresencechecker_p.h>
#include <QtProtobuf/private/qprotobufdeserializerbase_p.h>
#include <QtProtobuf/private/qprotobufregistration_p.h> #include <QtProtobuf/private/qprotobufregistration_p.h>
#include <QtProtobuf/private/qprotobufserializerbase_p.h> #include <QtProtobuf/private/qprotobufserializerbase_p.h>
#include <QtProtobuf/private/qtprotobufdefs_p.h> #include <QtProtobuf/private/qtprotobufdefs_p.h>
@ -19,7 +20,6 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <map>
#include <type_traits> #include <type_traits>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -85,6 +85,38 @@ private:
Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerImpl) Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerImpl)
}; };
class QProtobufJsonSerializerPrivate;
class QProtobufJsonDeserializerImpl final : public QProtobufDeserializerBase
{
public:
explicit QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent);
~QProtobufJsonDeserializerImpl();
void reset(QJsonObject obj);
void setError(QAbstractProtobufSerializer::Error error, QAnyStringView errorString) override;
void setUnexpectedEndOfStreamError();
void setInvalidFormatError();
private:
bool deserializeEnum(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
int nextFieldIndex(QProtobufMessage *message) override;
bool deserializeScalarField(QVariant &, const QtProtobufPrivate::QProtobufFieldInfo &) override;
struct JsonDeserializerState
{
JsonDeserializerState(const QJsonObject &obj) : obj(obj) { }
QJsonObject obj = {};
int index = 0;
QJsonValue scalarValue = {};
};
QList<JsonDeserializerState> m_state;
QProtobufJsonSerializerPrivate *m_parent = nullptr;
};
class QProtobufJsonSerializerPrivate final class QProtobufJsonSerializerPrivate final
{ {
Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate) Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate)
@ -211,7 +243,7 @@ public:
return QJsonValue(arr); return QJsonValue(arr);
} }
QProtobufJsonSerializerPrivate() QProtobufJsonSerializerPrivate() : deserializer(this)
{ {
[[maybe_unused]] static bool initialized = []() -> bool { [[maybe_unused]] static bool initialized = []() -> bool {
handlers[qMetaTypeId<QtProtobuf::int32>()] = createCommonHandler<QtProtobuf::int32>(); handlers[qMetaTypeId<QtProtobuf::int32>()] = createCommonHandler<QtProtobuf::int32>();
@ -274,17 +306,6 @@ public:
} }
~QProtobufJsonSerializerPrivate() = default; ~QProtobufJsonSerializerPrivate() = default;
[[nodiscard]] static QMetaEnum getMetaEnum(QMetaType enumMetaType)
{
const auto *metaObject = enumMetaType.metaObject();
Q_ASSERT(metaObject);
for (int i = 0; i < metaObject->enumeratorCount(); ++i) {
if (metaObject->enumerator(i).metaType() == enumMetaType)
return metaObject->enumerator(i);
}
return {};
}
template <typename T> template <typename T>
static QVariant deserializeCommon(const QJsonValue &value, bool &ok) static QVariant deserializeCommon(const QJsonValue &value, bool &ok)
{ {
@ -427,236 +448,15 @@ public:
return QVariant::fromValue(list); return QVariant::fromValue(list);
} }
static QtProtobuf::int64 deserializeEnum(const QJsonValue &value, const QMetaEnum &metaEnum,
bool &ok)
{
QtProtobuf::int64 result = 0;
if (value.isString()) {
QString enumKey = value.toString();
result = metaEnum.keyToValue(enumKey.toUtf8().data(), &ok);
}
if (ok)
return result;
result = deserialize<QtProtobuf::int64>(value, ok);
if (ok) {
ok = false;
// Make sure that it's the known enum value
for (int i = 0; i < metaEnum.keyCount(); ++i) {
if (metaEnum.value(i) == result) {
ok = true;
break;
}
}
}
return result;
}
QVariant deserializeValue(QVariant propertyData, bool &ok)
{
ok = false;
auto metaType = propertyData.metaType();
if (metaType.flags() & QMetaType::IsPointer) {
auto *messageProperty = propertyData.value<QProtobufMessage *>();
Q_ASSERT(messageProperty != nullptr);
ok = deserializeObject(messageProperty);
return propertyData;
}
if (propertyData.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
QProtobufRepeatedIterator propertyIt = propertyData.view<QProtobufRepeatedIterator>();
if (activeValue.isArray()) {
QJsonArray array = activeValue.toArray();
if (array.isEmpty()) {
ok = true;
activeValue = {};
return propertyData;
}
while (!array.isEmpty()
&& lastError == QAbstractProtobufSerializer::Error::None) {
activeValue = array.takeAt(0);
if (deserializeObject(propertyIt.addNext()))
propertyIt.push();
}
ok = propertyData.isValid();
} else {
while (!activeValue.isNull()
&& lastError == QAbstractProtobufSerializer::Error::None) {
if (deserializeObject(propertyIt.addNext()))
propertyIt.push();
}
}
ok = lastError == QAbstractProtobufSerializer::Error::None;
return propertyData;
}
auto handler = QtProtobufPrivate::findHandler(metaType);
if (handler.deserializer) {
while (!activeValue.isNull()
&& lastError == QAbstractProtobufSerializer::Error::None) {
handler
.deserializer([this](QProtobufMessage
*message) { return this->deserializeObject(message); },
propertyData.data());
}
ok = propertyData.isValid();
} else {
int userType = propertyData.userType();
auto handler = handlers.constFind(userType);
if (handler != handlers.constEnd() && handler.value().deserializer) {
propertyData = handler.value().deserializer(activeValue, ok);
if (!ok)
setInvalidFormatError();
} else {
setDeserializationError(QAbstractProtobufSerializer::Error::UnknownType,
QCoreApplication::
translate("QtProtobuf",
"No deserializer is registered for type %1")
.arg(userType));
}
}
return propertyData;
}
bool deserializeObject(QProtobufMessage *message)
{
Q_ASSERT(message != nullptr);
auto restoreOnReturn = qScopeGuard([prevCachedPropertyValue = cachedPropertyValue,
prevCachedIndex = cachedIndex, this]() {
cachedPropertyValue = prevCachedPropertyValue;
cachedIndex = prevCachedIndex;
});
cachedPropertyValue.clear();
cachedIndex = -1;
auto ordering = message->propertyOrdering();
Q_ASSERT(ordering != nullptr);
std::map<QString, QProtobufFieldInfo> msgContainer; // map<key, fieldInfo>
for (int index = 0; index < ordering->fieldCount(); ++index) {
int fieldIndex = ordering->fieldNumber(index);
Q_ASSERT_X(fieldIndex <= ProtobufFieldNumMax && fieldIndex >= ProtobufFieldNumMin, "",
"fieldIndex is out of range");
QProtobufFieldInfo fieldInfo(*ordering, index);
QString key = fieldInfo.jsonName().toString();
msgContainer.insert(std::pair<QString, QProtobufFieldInfo>(key, fieldInfo));
}
if (!activeValue.isObject()) {
setInvalidFormatError();
activeValue = {};
return false;
}
QJsonObject activeObject = activeValue.toObject();
// Go through QJSON doc and find keys that are presented in msgContainer
for (auto &key : activeObject.keys()) {
if (activeObject.value(key).isNull())
continue;
std::map<QString, QProtobufFieldInfo>::iterator iter = msgContainer
.find(key);
if (iter == msgContainer.end())
iter = msgContainer.find(convertJsonKeyToJsonName(key));
if (iter != msgContainer.end()) {
auto store = activeValue;
activeValue = activeObject.value(key);
if (auto index = ordering->indexOfFieldNumber(iter->second.fieldNumber());
index != cachedIndex) {
if (!storeCachedValue(message))
return false;
cachedPropertyValue = QtProtobufSerializerHelpers::messageProperty(message,
iter->second,
true);
cachedIndex = index;
}
bool ok = false;
const auto fieldFlags = iter->second.fieldFlags();
if (fieldFlags & QtProtobufPrivate::FieldFlag::Enum) {
if (fieldFlags & QtProtobufPrivate::FieldFlag::Repeated) {
QMetaType originalMetatype = cachedPropertyValue.metaType();
cachedPropertyValue
.setValue(deserializeList<QStringList, QString>(activeValue, ok));
if (ok)
ok = cachedPropertyValue.convert(originalMetatype);
} else {
const auto metaEnum = getMetaEnum(cachedPropertyValue.metaType());
Q_ASSERT(metaEnum.isValid());
cachedPropertyValue.setValue(deserializeEnum(activeValue, metaEnum, ok));
}
if (!ok)
setInvalidFormatError();
} else if (fieldFlags & QtProtobufPrivate::FieldFlag::Map) {
auto activeValueObj = activeValue.toObject();
for (auto it = activeValueObj.begin(); it != activeValueObj.end(); ++it) {
auto mapObj = QJsonObject{};
mapObj.insert("key"_L1, it.key());
mapObj.insert("value"_L1, it.value());
activeValue = mapObj;
cachedPropertyValue = deserializeValue(cachedPropertyValue, ok);
}
activeValue = store;
} else {
cachedPropertyValue = deserializeValue(cachedPropertyValue, ok);
activeValue = store;
}
if (!ok) {
cachedPropertyValue.clear();
cachedIndex = -1;
}
}
}
// Once all keys are deserialized we assume that activeValue is empty, nothing left
// to deserialize
activeValue = {};
return storeCachedValue(message);
}
void setDeserializationError(QAbstractProtobufSerializer::Error error,
const QString &errorString)
{
lastError = error;
lastErrorString = errorString;
}
void setUnexpectedEndOfStreamError()
{
setDeserializationError(QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
QCoreApplication::translate("QtProtobuf",
"JSON: Unexpected end of stream"));
}
void setInvalidFormatError()
{
setDeserializationError(QAbstractProtobufSerializer::Error::InvalidFormat,
QCoreApplication::
translate("QtProtobuf",
"JSON: One or more fields have invalid format"));
}
void clearError(); void clearError();
QAbstractProtobufSerializer::Error lastError = QAbstractProtobufSerializer::Error::None; QAbstractProtobufSerializer::Error lastError = QAbstractProtobufSerializer::Error::None;
QString lastErrorString; QString lastErrorString;
QJsonValue activeValue;
static SerializerRegistry handlers; static SerializerRegistry handlers;
[[nodiscard]] bool storeCachedValue(QProtobufMessage *message);
QVariant cachedPropertyValue;
int cachedIndex = -1;
QProtobufJsonSerializerImpl serializer; QProtobufJsonSerializerImpl serializer;
QProtobufJsonDeserializerImpl deserializer;
}; };
QProtobufJsonSerializerImpl::~QProtobufJsonSerializerImpl() = default; QProtobufJsonSerializerImpl::~QProtobufJsonSerializerImpl() = default;
@ -741,20 +541,171 @@ void QProtobufJsonSerializerImpl::serializeMessageFieldEnd(const QProtobufMessag
m_result = store; m_result = store;
} }
bool QProtobufJsonSerializerPrivate::storeCachedValue(QProtobufMessage *message) QProtobufJsonDeserializerImpl::QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent)
: m_parent(parent)
{ {
bool ok = true; }
if (cachedIndex >= 0 && !cachedPropertyValue.isNull()) {
const auto *ordering = message->propertyOrdering(); QProtobufJsonDeserializerImpl::~QProtobufJsonDeserializerImpl()
QProtobufFieldInfo fieldInfo(*ordering, cachedIndex); = default;
ok = QtProtobufSerializerHelpers::setMessageProperty(message, fieldInfo,
cachedPropertyValue); void QProtobufJsonDeserializerImpl::reset(QJsonObject obj)
cachedPropertyValue.clear(); {
cachedIndex = -1; m_state.clear();
if (!obj.isEmpty())
m_state.push_back({ obj });
}
void QProtobufJsonDeserializerImpl::setError(QAbstractProtobufSerializer::Error error,
QAnyStringView errorString)
{
m_parent->lastError = error;
m_parent->lastErrorString = errorString.toString();
}
bool QProtobufJsonDeserializerImpl::deserializeEnum(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo
&fieldInfo)
{
bool ok = false;
auto &state = m_state.last();
if (fieldInfo.fieldFlags().testFlag(QtProtobufPrivate::FieldFlag::Repeated)) {
value = QProtobufJsonSerializerPrivate::deserializeList<QStringList,
QString>(state.scalarValue, ok);
} else {
// It's allowed to pass single enum value as numeric value.
// Make the backward value conversion and deserialize enum as QtProtobuf::int64.
if (state.scalarValue.isString()) {
value = QProtobufJsonSerializerPrivate::deserializeCommon<QString>(state.scalarValue,
ok);
} else {
value = QProtobufJsonSerializerPrivate::deserializeCommon<
QtProtobuf::int64>(state.scalarValue, ok);
}
} }
return ok; return ok;
} }
int QProtobufJsonDeserializerImpl::nextFieldIndex(QProtobufMessage *message)
{
const auto *ordering = message->propertyOrdering();
const int fieldCount = ordering->fieldCount();
if (fieldCount == 0)
return -1;
JsonDeserializerState &state = m_state.last();
state.scalarValue = {};
while (state.index < fieldCount) {
const auto jsonName = ordering->jsonName(state.index);
const auto keys = state.obj.keys();
const auto it = std::find_if(keys.constBegin(), keys.constEnd(),
[&jsonName](const auto &val) {
return jsonName == val
|| jsonName == convertJsonKeyToJsonName(val);
});
if (it == keys.constEnd()) {
++state.index;
continue;
}
QtProtobufPrivate::FieldFlags flags = ordering->fieldFlags(state.index);
QJsonValue val = state.obj.value(*it);
if (val.isNull()) {
++state.index;
continue;
}
int index = state.index;
if (flags.testFlags({ QtProtobufPrivate::FieldFlag::Message,
QtProtobufPrivate::FieldFlag::Repeated })) {
if (!val.isArray()) {
setInvalidFormatError();
return -1;
}
auto array = val.toArray();
if (array.isEmpty()) {
++state.index;
continue;
}
if (!array.at(0).isObject()) {
setInvalidFormatError();
return -1;
}
auto nextObject = array.takeAt(0).toObject();
state.obj.insert(*it, array);
m_state.push_back({ nextObject });
} else if (flags.testFlag(QtProtobufPrivate::FieldFlag::Map)) {
if (!val.isObject()) {
setInvalidFormatError();
return -1;
}
auto mapObject = val.toObject();
if (mapObject.isEmpty()) {
++state.index;
continue;
}
QString key = mapObject.begin().key();
QJsonObject nextObject;
nextObject.insert("key"_L1, key);
nextObject.insert("value"_L1, mapObject.take(key));
state.obj.insert(*it, mapObject);
m_state.push_back({ nextObject });
} else if (flags.testFlag(QtProtobufPrivate::FieldFlag::Message)) {
if (!val.isObject()) {
setInvalidFormatError();
return -1;
}
auto nextObject = val.toObject();
++state.index;
m_state.push_back({ nextObject });
} else {
state.scalarValue = val;
++state.index;
}
return index;
}
m_state.pop_back();
return -1;
}
bool QProtobufJsonDeserializerImpl::deserializeScalarField(QVariant &value,
const QProtobufFieldInfo &)
{
auto handler = QProtobufJsonSerializerPrivate::handlers.constFind(value.userType());
if (handler == QProtobufJsonSerializerPrivate::handlers.constEnd()
|| !handler.value().deserializer) {
return false;
}
bool ok = false;
value = handler.value().deserializer(m_state.last().scalarValue, ok);
if (!ok)
setInvalidFormatError();
return true;
}
void QProtobufJsonDeserializerImpl::setUnexpectedEndOfStreamError()
{
setError(QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
QCoreApplication::translate("QtProtobuf", "JSON: Unexpected end of stream"));
}
void QProtobufJsonDeserializerImpl::setInvalidFormatError()
{
setError(QAbstractProtobufSerializer::Error::InvalidFormat,
QCoreApplication::translate("QtProtobuf",
"JSON: One or more fields have invalid format"));
}
QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {}; QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {};
void QProtobufJsonSerializerPrivate::clearError() void QProtobufJsonSerializerPrivate::clearError()
@ -804,19 +755,22 @@ bool QProtobufJsonSerializer::deserializeMessage(QProtobufMessage *message,
QJsonParseError err; QJsonParseError err;
auto document = QJsonDocument::fromJson(data.toByteArray(), &err); auto document = QJsonDocument::fromJson(data.toByteArray(), &err);
if (err.error != QJsonParseError::NoError) { if (err.error != QJsonParseError::NoError) {
d_ptr->setUnexpectedEndOfStreamError(); d_ptr->deserializer.setUnexpectedEndOfStreamError();
return false; return false;
} }
if (!document.isObject()) { if (!document.isObject()) {
d_ptr->setInvalidFormatError(); d_ptr->deserializer.setInvalidFormatError();
return false; return false;
} }
d_ptr->activeValue = document.object();
d_ptr->cachedPropertyValue.clear(); if (auto obj = document.object(); !obj.isEmpty()) {
d_ptr->cachedIndex = -1; d_ptr->deserializer.reset(obj);
return d_ptr->deserializeObject(message); bool result = d_ptr->deserializer.deserializeMessage(message);
d_ptr->deserializer.reset({});
return result;
}
return true;
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -287,6 +287,236 @@ QByteArray QProtobufSerializerImpl::encodeHeader(int fieldIndex, QtProtobuf::Wir
return QProtobufSerializerPrivate::serializeVarintCommon<uint32_t>(header); return QProtobufSerializerPrivate::serializeVarintCommon<uint32_t>(header);
} }
QProtobufDeserializerImpl::QProtobufDeserializerImpl(QProtobufSerializerPrivate *parent)
: m_parent(parent)
{
}
QProtobufDeserializerImpl::~QProtobufDeserializerImpl()
= default;
void QProtobufDeserializerImpl::reset(QByteArrayView data)
{
m_it = QProtobufSelfcheckIterator::fromView(data);
m_state.push_back(data.end());
clearCachedValue();
}
void QProtobufDeserializerImpl::setError(QAbstractProtobufSerializer::Error error,
QAnyStringView errorString)
{
m_parent->lastError = error;
m_parent->lastErrorString = errorString.toString();
}
bool QProtobufDeserializerImpl::deserializeEnum(QVariant &value,
const QProtobufFieldInfo &fieldInfo)
{
const auto fieldFlags = fieldInfo.fieldFlags();
if (fieldFlags.testFlag(QtProtobufPrivate::FieldFlag::Repeated)) {
QMetaType metaType = value.metaType();
value.convert(QMetaType::fromType<QList<QtProtobuf::int64>>());
bool result = false;
if (m_wireType == QtProtobuf::WireTypes::Varint) {
result = QProtobufSerializerPrivate::deserializeNonPackedList<QtProtobuf::int64>(m_it,
value);
} else if (m_wireType == QtProtobuf::WireTypes::LengthDelimited) {
result = QProtobufSerializerPrivate::deserializeList<QtProtobuf::int64>(m_it, value);
}
value.convert(metaType);
return result;
}
return QProtobufSerializerPrivate::deserializeBasic<QtProtobuf::int64>(m_it, value);
}
int QProtobufDeserializerImpl::nextFieldIndex(QProtobufMessage *message)
{
Q_ASSERT(message);
const auto *ordering = message->propertyOrdering();
Q_ASSERT(ordering != nullptr);
while (m_it.isValid() && m_it != m_state.last()) {
// Each iteration we expect iterator is setup to beginning of next chunk
int fieldNumber = QtProtobuf::InvalidFieldNumber;
const QProtobufSelfcheckIterator fieldBegin = m_it; // copy this, we may need it later
if (!decodeHeader(m_it, fieldNumber, m_wireType)) {
setError(QAbstractProtobufSerializer::Error::InvalidHeader,
"Message received doesn't contain valid header byte.");
return -1;
}
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.
if (auto length = skipField(fieldBegin); length < 0) {
return -1;
} else if (length > 0 && m_parent->preserveUnknownFields) {
QByteArrayView fieldData(fieldBegin.data(), length);
QProtobufMessagePrivate::storeUnknownEntry(message, fieldData, fieldNumber);
}
continue;
}
if (ordering->fieldFlags(index).testAnyFlags({ QtProtobufPrivate::FieldFlag::Message,
QtProtobufPrivate::FieldFlag::Map })) {
auto
opt = QProtobufSerializerPrivate::deserializeVarintCommon<QtProtobuf::uint64>(m_it);
if (!opt) {
setUnexpectedEndOfStreamError();
return -1;
}
quint64 length = *opt;
if (!m_it.isValid() || quint64(m_it.bytesLeft()) < length
|| length > quint64(QByteArray::maxSize())) {
setUnexpectedEndOfStreamError();
return -1;
}
m_state.push_back(m_it.data() + length);
}
return index;
}
if (!m_it.isValid())
setUnexpectedEndOfStreamError();
m_state.pop_back();
return -1;
}
bool QProtobufDeserializerImpl::deserializeScalarField(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo
&fieldInfo)
{
QMetaType metaType = value.metaType();
bool isNonPacked = fieldInfo.fieldFlags().testFlag(QtProtobufPrivate::FieldFlag::NonPacked);
auto basicHandler = findIntegratedTypeHandler(metaType, isNonPacked);
if (!basicHandler)
return false;
if (basicHandler->wireType != m_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 != m_wireType) {
setError(QAbstractProtobufSerializer::Error::InvalidHeader,
QCoreApplication::translate("QtProtobuf",
"Invalid wiretype for the %1 "
"field number %1. Expected %2, received %3")
.arg(QString::fromUtf8(metaType.name()))
.arg(fieldInfo.fieldNumber())
.arg(basicHandler ? static_cast<int>(basicHandler->wireType) : -1)
.arg(static_cast<int>(m_wireType)));
value.clear();
return true;
}
}
if (!basicHandler->deserializer(m_it, value)) {
value.clear();
setUnexpectedEndOfStreamError();
}
return true;
}
qsizetype QProtobufDeserializerImpl::skipField(const QProtobufSelfcheckIterator &fieldBegin)
{
switch (m_wireType) {
case QtProtobuf::WireTypes::Varint:
skipVarint();
break;
case QtProtobuf::WireTypes::Fixed32:
m_it += sizeof(decltype(QtProtobuf::fixed32::t));
break;
case QtProtobuf::WireTypes::Fixed64:
m_it += sizeof(decltype(QtProtobuf::fixed64::t));
break;
case QtProtobuf::WireTypes::LengthDelimited:
skipLengthDelimited();
break;
case QtProtobuf::WireTypes::Unknown:
default:
Q_UNREACHABLE();
return 0;
}
if (!m_it.isValid()) {
setUnexpectedEndOfStreamError();
return -1;
}
return std::distance(fieldBegin, m_it);
}
void QProtobufDeserializerImpl::skipVarint()
{
while ((*m_it) & 0x80)
++m_it;
++m_it;
}
void QProtobufDeserializerImpl::skipLengthDelimited()
{
//Get length of length-delimited field
auto opt = QProtobufSerializerPrivate::deserializeVarintCommon<QtProtobuf::uint64>(m_it);
if (!opt) {
m_it += m_it.bytesLeft() + 1;
return;
}
QtProtobuf::uint64 length = opt.value();
m_it += length;
}
void QProtobufDeserializerImpl::setUnexpectedEndOfStreamError()
{
setError(QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
QCoreApplication::translate("QtProtobuf", "Unexpected end of stream"));
}
bool QProtobufDeserializerImpl::decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex,
QtProtobuf::WireTypes &wireType)
{
if (it.bytesLeft() == 0)
return false;
auto opt = QProtobufSerializerPrivate::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);
}
QProtobufSerializerPrivate::QProtobufSerializerPrivate() : deserializer(this)
{
}
void QProtobufSerializerPrivate::clearError()
{
lastError = QAbstractProtobufSerializer::Error::None;
lastErrorString.clear();
}
/*! /*!
Constructs a new serializer instance. Constructs a new serializer instance.
*/ */
@ -310,327 +540,13 @@ QByteArray QProtobufSerializer::serializeMessage(const QProtobufMessage *message
return result; return result;
} }
void QProtobufSerializerPrivate::setUnexpectedEndOfStreamError()
{
setDeserializationError(QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
QCoreApplication::translate("QtProtobuf", "Unexpected end of stream"));
}
void QProtobufSerializerPrivate::clearError()
{
lastError = QAbstractProtobufSerializer::Error::None;
lastErrorString.clear();
}
bool QProtobufSerializer::deserializeMessage(QProtobufMessage *message, QByteArrayView data) const bool QProtobufSerializer::deserializeMessage(QProtobufMessage *message, QByteArrayView data) const
{ {
d_ptr->clearCachedValue();
d_ptr->clearError(); d_ptr->clearError();
d_ptr->it = QProtobufSelfcheckIterator::fromView(data); d_ptr->deserializer.reset(data);
d_ptr->deserializer.deserializeMessage(message);
bool ok = true; d_ptr->deserializer.reset({});
while (d_ptr->it.isValid() && d_ptr->it != data.end()) { return d_ptr->lastError == QAbstractProtobufSerializer::Error::None;
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();
}
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 prevCachedRepeatedIterator = std::move(cachedRepeatedIterator);
auto restoreOnReturn = qScopeGuard([prevIt = it, prevCachedPropertyValue = cachedPropertyValue,
prevCachedIndex = cachedIndex, &prevCachedRepeatedIterator,
this]() {
it = prevIt;
cachedPropertyValue = prevCachedPropertyValue;
cachedIndex = prevCachedIndex;
cachedRepeatedIterator = std::move(prevCachedRepeatedIterator);
});
clearCachedValue();
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();
}
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;
}
/*!
\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));
}
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::Error::InvalidHeader,
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) {
QProtobufMessagePrivate::storeUnknownEntry(message,
QByteArrayView(itBeforeHeader.data(),
length),
fieldNumber);
}
return true;
}
QProtobufFieldInfo fieldInfo(*ordering, index);
if (cachedIndex != index) {
if (!storeCachedValue(message))
return false;
cachedPropertyValue = QtProtobufSerializerHelpers::messageProperty(message, 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.fieldFlags();
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::FieldFlag::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::Error::InvalidHeader,
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;
}
return true;
}
if (cachedPropertyValue.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
if (!cachedRepeatedIterator.isValid()) {
cachedRepeatedIterator = cachedPropertyValue.view<QProtobufRepeatedIterator>();
}
if (deserializeObject(cachedRepeatedIterator.addNext())) {
cachedRepeatedIterator.push();
return true;
}
return false;
}
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::Error::UnknownType,
QCoreApplication::translate("QtProtobuf", error.toUtf8().data()));
return false;
}
handler.deserializer([this](QProtobufMessage
*message) { return this->deserializeObject(message); },
cachedPropertyValue.data());
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 = QtProtobufSerializerHelpers::setMessageProperty(message, fieldInfo,
cachedPropertyValue);
clearCachedValue();
}
return ok;
}
void QProtobufSerializerPrivate::clearCachedValue()
{
cachedPropertyValue.clear();
cachedIndex = -1;
cachedRepeatedIterator = QProtobufRepeatedIterator();
} }
/*! /*!
@ -651,13 +567,6 @@ QString QProtobufSerializer::lastErrorString() const
return d_ptr->lastErrorString; return d_ptr->lastErrorString;
} }
void QProtobufSerializerPrivate::setDeserializationError(
QAbstractProtobufSerializer::Error error, const QString &errorString)
{
lastError = error;
lastErrorString = errorString;
}
/*! /*!
Controls whether the unknown fields received from the wire should be Controls whether the unknown fields received from the wire should be
stored in the resulting message or if it should be omitted, based stored in the resulting message or if it should be omitted, based

View File

@ -23,9 +23,10 @@
#include <QtProtobuf/qtprotobuftypes.h> #include <QtProtobuf/qtprotobuftypes.h>
#include <QtProtobuf/private/protobuffieldpresencechecker_p.h> #include <QtProtobuf/private/protobuffieldpresencechecker_p.h>
#include <QtProtobuf/private/qtprotobuflogging_p.h>
#include <QtProtobuf/private/qprotobufdeserializerbase_p.h>
#include <QtProtobuf/private/qprotobufselfcheckiterator_p.h> #include <QtProtobuf/private/qprotobufselfcheckiterator_p.h>
#include <QtProtobuf/private/qprotobufserializerbase_p.h> #include <QtProtobuf/private/qprotobufserializerbase_p.h>
#include <QtProtobuf/private/qtprotobuflogging_p.h>
#include <QtCore/qendian.h> #include <QtCore/qendian.h>
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
@ -68,6 +69,40 @@ private:
Q_DISABLE_COPY_MOVE(QProtobufSerializerImpl) Q_DISABLE_COPY_MOVE(QProtobufSerializerImpl)
}; };
class QProtobufDeserializerImpl final : public QProtobufDeserializerBase
{
public:
explicit QProtobufDeserializerImpl(QProtobufSerializerPrivate *parent);
~QProtobufDeserializerImpl();
void reset(QByteArrayView data);
QProtobufSelfcheckIterator m_it;
private:
void setError(QAbstractProtobufSerializer::Error error, QAnyStringView errorString) override;
bool deserializeEnum(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
int nextFieldIndex(QProtobufMessage *message) override;
bool deserializeScalarField(QVariant &value,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
qsizetype skipField(const QProtobufSelfcheckIterator &fieldBegin);
void skipVarint();
void skipLengthDelimited();
void setUnexpectedEndOfStreamError();
[[nodiscard]]
static bool decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex,
QtProtobuf::WireTypes &wireType);
QtProtobuf::WireTypes m_wireType = QtProtobuf::WireTypes::Unknown;
QList<QByteArrayView::iterator> m_state;
QProtobufSerializerPrivate *m_parent = nullptr;
Q_DISABLE_COPY_MOVE(QProtobufDeserializerImpl)
};
class QProtobufSerializerPrivate class QProtobufSerializerPrivate
{ {
// The below type trait structures help to determine the required encoding method for protobuf // The below type trait structures help to determine the required encoding method for protobuf
@ -175,7 +210,7 @@ public:
QtProtobuf::WireTypes wireType; // Serialization WireType QtProtobuf::WireTypes wireType; // Serialization WireType
}; };
QProtobufSerializerPrivate() = default; QProtobufSerializerPrivate();
~QProtobufSerializerPrivate() = default; ~QProtobufSerializerPrivate() = default;
// ########################################################################### // ###########################################################################
// Serializers // Serializers
@ -487,10 +522,6 @@ public:
return { result }; return { result };
} }
[[nodiscard]]
static bool decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex,
QtProtobuf::WireTypes &wireType);
/*! /*!
Gets length of a byte-array and prepends to it its serialized length value Gets length of a byte-array and prepends to it its serialized length value
using the appropriate serialization algorithm using the appropriate serialization algorithm
@ -515,40 +546,16 @@ public:
return s(variantValue.value<T>(), header); return s(variantValue.value<T>(), header);
} }
// this set of 3 methods is used to skip bytes corresponding to an unexpected property
// in a serialized message met while the message being deserialized
static qsizetype skipSerializedFieldBytes(QProtobufSelfcheckIterator &it,
QtProtobuf::WireTypes type);
static void skipVarint(QProtobufSelfcheckIterator &it);
static void skipLengthDelimited(QProtobufSelfcheckIterator &it);
bool deserializeObject(QProtobufMessage *message);
bool deserializeEnumList(QList<QtProtobuf::int64> &value);
[[nodiscard]] bool deserializeProperty(QProtobufMessage *message);
void setDeserializationError(QAbstractProtobufSerializer::Error error,
const QString &errorString);
void clearError(); void clearError();
void setUnexpectedEndOfStreamError();
[[nodiscard]] bool storeCachedValue(QProtobufMessage *message);
void clearCachedValue();
QAbstractProtobufSerializer::Error lastError = QAbstractProtobufSerializer::Error lastError =
QAbstractProtobufSerializer::Error::UnknownType; QAbstractProtobufSerializer::Error::UnknownType;
QString lastErrorString; QString lastErrorString;
QProtobufSelfcheckIterator it;
bool preserveUnknownFields = true; bool preserveUnknownFields = true;
QVariant cachedPropertyValue;
QProtobufRepeatedIterator cachedRepeatedIterator;
int cachedIndex = -1;
QProtobufSerializerImpl serializer; QProtobufSerializerImpl serializer;
QProtobufDeserializerImpl deserializer;
private: private:
Q_DISABLE_COPY_MOVE(QProtobufSerializerPrivate) Q_DISABLE_COPY_MOVE(QProtobufSerializerPrivate)

View File

@ -1,4 +1,3 @@
Required.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.ProtobufOutput
Required.Proto3.JsonInput.Any.JsonOutput Required.Proto3.JsonInput.Any.JsonOutput
Required.Proto3.JsonInput.Any.ProtobufOutput Required.Proto3.JsonInput.Any.ProtobufOutput
Required.Proto3.JsonInput.AnyNested.JsonOutput Required.Proto3.JsonInput.AnyNested.JsonOutput
@ -105,7 +104,6 @@ Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
Required.Proto3.JsonInput.ValueAcceptObject.ProtobufOutput Required.Proto3.JsonInput.ValueAcceptObject.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptString.JsonOutput Required.Proto3.JsonInput.ValueAcceptString.JsonOutput
Required.Proto3.JsonInput.ValueAcceptString.ProtobufOutput Required.Proto3.JsonInput.ValueAcceptString.ProtobufOutput
Required.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.JsonOutput
Required.DurationProtoInputTooLarge.JsonOutput Required.DurationProtoInputTooLarge.JsonOutput
Required.DurationProtoInputTooSmall.JsonOutput Required.DurationProtoInputTooSmall.JsonOutput
Required.TimestampProtoInputTooLarge.JsonOutput Required.TimestampProtoInputTooLarge.JsonOutput

View File

@ -260,14 +260,14 @@ void QtProtobufRepeatedTypesJsonDeserializationTest::invalidTypeTest()
// expected sint, string is used // expected sint, string is used
RepeatedSInt64Message test; RepeatedSInt64Message test;
test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,\"abcd\",12324523123123,-3,3]}"_ba); test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,\"abcd\",12324523123123,-3,3]}"_ba);
QVERIFY(test.testRepeatedInt().size() == 0); QCOMPARE(test.testRepeatedInt().size(), 2);
QCOMPARE(serializer->lastError(), QAbstractProtobufSerializer::Error::InvalidFormat); QCOMPARE(serializer->lastError(), QAbstractProtobufSerializer::Error::InvalidFormat);
// expected bool, float is used // expected bool, float is used
RepeatedBoolMessage boolMsg; RepeatedBoolMessage boolMsg;
boolMsg.deserialize(serializer.get(), boolMsg.deserialize(serializer.get(),
"{\"testRepeatedBool\":[true,true,true,7.8,false,false,false,false,false,false,false,false,true]}"_ba); "{\"testRepeatedBool\":[true,true,true,7.8,false,false,false,false,false,false,false,false,true]}"_ba);
QVERIFY(test.testRepeatedInt().size() == 0); QCOMPARE(boolMsg.testRepeatedBool().size(), 3);
QCOMPARE(serializer->lastError(), QAbstractProtobufSerializer::Error::InvalidFormat); QCOMPARE(serializer->lastError(), QAbstractProtobufSerializer::Error::InvalidFormat);
} }