1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include <QtProtobuf/qprotobufjsonserializer.h>
6
7#include <QtProtobuf/private/qtprotobuf-config_p.h>
8#include <QtProtobuf/private/protobuffieldpresencechecker_p.h>
9#include <QtProtobuf/private/protobufscalarjsonserializers_p.h>
10#include <QtProtobuf/private/qprotobufdeserializerbase_p.h>
11#include <QtProtobuf/private/qprotobufjsonserializer_p.h>
12#include <QtProtobuf/private/qprotobufregistration_p.h>
13#include <QtProtobuf/private/qprotobufserializerbase_p.h>
14#include <QtProtobuf/private/qtprotobufdefs_p.h>
15#include <QtProtobuf/private/qtprotobufserializerhelpers_p.h>
16
17#include <QtCore/qcoreapplication.h>
18#include <QtCore/qdatetime.h>
19#include <QtCore/qhash.h>
20#include <QtCore/qjsonarray.h>
21#include <QtCore/qjsondocument.h>
22#include <QtCore/qjsonobject.h>
23#if !QT_CONFIG(protobuf_unsafe_registry)
24# include <QtCore/qreadwritelock.h>
25#endif
26#include <QtCore/qtimezone.h>
27#include <QtCore/qvariant.h>
28
29#include <cmath>
30
31QT_BEGIN_NAMESPACE
32
33/*!
34 \class QProtobufJsonSerializer
35 \inmodule QtProtobuf
36 \since 6.7
37 \brief The QProtobufJsonSerializer class is an interface that represents
38 basic functions for serialization/deserialization of QProtobufMessage
39 objects to JSON.
40
41 The QProtobufJsonSerializer class registers serializers/deserializers for
42 classes implementing a protobuf message, inheriting \l QProtobufMessage. These
43 classes are generated automatically, based on a \c{.proto} file, using the CMake
44 function \l qt_add_protobuf or by running
45 \l {The qtprotobufgen Tool} {qtprotobufgen} directly.
46*/
47
48using namespace Qt::StringLiterals;
49using namespace QtProtobufPrivate;
50using namespace ProtobufScalarJsonSerializers;
51
52namespace {
53
54struct JsonHandlerRegistry
55{
56 void registerHandler(QMetaType metaType, QtProtobufPrivate::CustomJsonSerializer serializer,
57 QtProtobufPrivate::CustomJsonDeserializer deserializer)
58 {
59#if !QT_CONFIG(protobuf_unsafe_registry)
60 QWriteLocker locker(&m_lock);
61#endif
62 m_registry[metaType] = { serializer, deserializer };
63 }
64
65 QtProtobufPrivate::CustomJsonSerializer findSerializer(QMetaType metaType)
66 {
67#if !QT_CONFIG(protobuf_unsafe_registry)
68 QReadLocker locker(&m_lock);
69#endif
70 const auto it = m_registry.constFind(key: metaType);
71 if (it != m_registry.constEnd())
72 return it.value().first;
73 return nullptr;
74 }
75
76 QtProtobufPrivate::CustomJsonDeserializer findDeserializer(QMetaType metaType)
77 {
78#if !QT_CONFIG(protobuf_unsafe_registry)
79 QReadLocker locker(&m_lock);
80#endif
81 const auto it = m_registry.constFind(key: metaType);
82 if (it != m_registry.constEnd())
83 return it.value().second;
84 return nullptr;
85 }
86
87private:
88 using Handler = std::pair<QtProtobufPrivate::CustomJsonSerializer,
89 QtProtobufPrivate::CustomJsonDeserializer>;
90#if !QT_CONFIG(protobuf_unsafe_registry)
91 QReadWriteLock m_lock;
92#endif
93 QHash<QMetaType, Handler> m_registry;
94};
95Q_GLOBAL_STATIC(JsonHandlerRegistry, jsonHandlersRegistry)
96
97inline QString convertJsonKeyToJsonName(QStringView name)
98{
99 QString result;
100 result.reserve(asize: name.size());
101 bool nextUpperCase = false;
102 for (const auto &c : name) {
103 if (c == QChar::fromLatin1(c: '_')) {
104 nextUpperCase = true;
105 continue;
106 }
107 result.append(c: nextUpperCase ? c.toUpper() : c);
108 nextUpperCase = false;
109 }
110 return result;
111}
112
113}
114
115void QtProtobufPrivate::registerCustomJsonHandler(QMetaType metaType,
116 QtProtobufPrivate::CustomJsonSerializer
117 serializer,
118 QtProtobufPrivate::CustomJsonDeserializer
119 deserializer)
120{
121 jsonHandlersRegistry->registerHandler(metaType, serializer, deserializer);
122}
123
124QtProtobufPrivate::CustomJsonSerializer
125QtProtobufPrivate::findCustomJsonSerializer(QMetaType metaType)
126{
127 return jsonHandlersRegistry->findSerializer(metaType);
128}
129
130QtProtobufPrivate::CustomJsonDeserializer
131QtProtobufPrivate::findCustomJsonDeserializer(QMetaType metaType)
132{
133 return jsonHandlersRegistry->findDeserializer(metaType);
134}
135
136class QProtobufJsonSerializerImpl final : public QProtobufSerializerBase
137{
138public:
139 QProtobufJsonSerializerImpl() = default;
140 ~QProtobufJsonSerializerImpl();
141
142 const QJsonObject &result() const { return m_result; }
143
144 void reset();
145
146protected:
147 void serializeMessageField(const QProtobufMessage *message,
148 const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
149
150private:
151 bool serializeEnum(QVariant &value, const QProtobufFieldInfo &fieldInfo) override;
152 bool serializeScalarField(const QVariant &value, const QProtobufFieldInfo &fieldInfo) override;
153 void serializeMessageFieldBegin() override;
154 void serializeMessageFieldEnd(const QProtobufMessage *message,
155 const QProtobufFieldInfo &fieldInfo) override;
156
157 QJsonObject m_result;
158 QList<QJsonObject> m_state;
159
160 Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerImpl)
161};
162
163class QProtobufJsonSerializerPrivate;
164class QProtobufJsonDeserializerImpl final : public QProtobufDeserializerBase
165{
166public:
167 explicit QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent);
168 ~QProtobufJsonDeserializerImpl();
169
170 void reset(QJsonObject obj);
171
172 void setError(QAbstractProtobufSerializer::Error error, QAnyStringView errorString) override;
173 void setUnexpectedEndOfStreamError();
174 void setInvalidFormatError();
175
176protected:
177 bool deserializeMessageField(QProtobufMessage *message) override;
178
179private:
180 bool deserializeEnum(QVariant &value,
181 const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) override;
182 int nextFieldIndex(QProtobufMessage *message) override;
183 bool deserializeScalarField(QVariant &, const QtProtobufPrivate::QProtobufFieldInfo &) override;
184
185 struct JsonDeserializerState
186 {
187 JsonDeserializerState(const QJsonObject &obj) : obj(obj) { }
188
189 QJsonObject obj = {};
190 int index = 0;
191 QJsonValue scalarValue = {QJsonValue::Undefined};
192 };
193
194 QList<JsonDeserializerState> m_state;
195 QProtobufJsonSerializerPrivate *m_parent = nullptr;
196};
197
198class QProtobufJsonSerializerPrivate final
199{
200 Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate)
201public:
202 using Serializer = std::function<QJsonValue(const QVariant &)>;
203 using Deserializer = std::function<QVariant(const QJsonValue&, bool &ok)>;
204
205 struct SerializationHandlers {
206 // serializer assigned to class
207 Serializer serializer;
208 // deserializer assigned to class
209 Deserializer deserializer;
210 ProtobufFieldPresenceChecker::Function isPresent;
211 };
212
213 template <typename T>
214 static SerializationHandlers createCommonHandler()
215 {
216 return { serializeCommon<T>, deserializeCommon<T>,
217 ProtobufFieldPresenceChecker::isPresent<T> };
218 }
219
220 template <typename L, typename T>
221 static SerializationHandlers createCommonListHandler()
222 {
223 return { serializeList<L>, deserializeList<L, T>,
224 ProtobufFieldPresenceChecker::isPresent<L> };
225 }
226
227 template<typename T, if_json_floating_point<T> = true>
228 static bool isPresent(const QVariant &value)
229 {
230 const T val = value.value<T>();
231 return val != 0 || std::signbit(val);
232 }
233
234 using SerializerRegistry = QHash<int/*metatypeid*/, SerializationHandlers>;
235
236 QProtobufJsonSerializerPrivate();
237 ~QProtobufJsonSerializerPrivate() = default;
238
239 void clearError();
240
241 QAbstractProtobufSerializer::Error lastError = QAbstractProtobufSerializer::Error::None;
242 QString lastErrorString;
243
244 static SerializerRegistry handlers;
245
246 QProtobufJsonSerializerImpl serializer;
247 QProtobufJsonDeserializerImpl deserializer;
248};
249
250QProtobufJsonSerializerImpl::~QProtobufJsonSerializerImpl() = default;
251
252void QProtobufJsonSerializerImpl::reset()
253{
254 m_result = {};
255 m_state.clear();
256}
257
258void QProtobufJsonSerializerImpl::serializeMessageField(const QProtobufMessage *message,
259 const QtProtobufPrivate::QProtobufFieldInfo
260 &fieldInfo)
261{
262 if (!message)
263 return;
264
265 const auto *metaObject = QtProtobufSerializerHelpers::messageMetaObject(message);
266
267 if (auto *serializer = QtProtobufPrivate::findCustomJsonSerializer(metaType: metaObject->metaType())) {
268 if (const QJsonValue value = serializer(message); !value.isUndefined()) {
269 if (fieldInfo.fieldFlags().testAnyFlags(flags: QtProtobufPrivate::FieldFlag::Repeated)) {
270 auto array = m_result.value(key: fieldInfo.jsonName().toString()).toArray();
271 array.append(value);
272 m_result.insert(key: fieldInfo.jsonName().toString(), value: array);
273 } else {
274 m_result.insert(key: fieldInfo.jsonName().toString(), value);
275 }
276 }
277 } else {
278 QProtobufSerializerBase::serializeMessageField(message, fieldInfo);
279 }
280}
281
282bool QProtobufJsonSerializerImpl::serializeEnum(QVariant &value,
283 const QProtobufFieldInfo &fieldInfo)
284
285{
286 const auto jsonName = fieldInfo.jsonName();
287 if (fieldInfo.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) {
288 if (!value.convert(type: QMetaType::fromType<QStringList>()))
289 return false;
290 if (!ProtobufFieldPresenceChecker::isPresent<QStringList>(value))
291 return true;
292 m_result.insert(key: jsonName.toString(), value: serializeList<QStringList>(propertyValue: value));
293 } else {
294 if (!value.convert(type: QMetaType::fromType<QString>()))
295 return false;
296 if (!ProtobufFieldPresenceChecker::isPresent<QString>(value)
297 && !isOneofOrOptionalField(flags: fieldInfo.fieldFlags())) {
298 return true;
299 }
300 m_result.insert(key: jsonName.toString(), value: serializeCommon<QString>(propertyValue: value));
301 }
302 return true;
303}
304
305bool QProtobufJsonSerializerImpl::serializeScalarField(const QVariant &value,
306 const QProtobufFieldInfo &fieldInfo)
307{
308 const auto it = QProtobufJsonSerializerPrivate::handlers.constFind(key: value.userType());
309 // Is not a protobuf scalar value type
310 if (it == QProtobufJsonSerializerPrivate::handlers.cend())
311 return false;
312
313 // Field is empty
314 if (!it->isPresent(value) && !isOneofOrOptionalField(flags: fieldInfo.fieldFlags()))
315 return true;
316
317 // If serializer is not defined we should use the standard QJsonValue cast from variant
318 m_result.insert(key: fieldInfo.jsonName().toString(),
319 value: it->serializer ? it->serializer(value) : QJsonValue::fromVariant(variant: value));
320 return true;
321}
322
323void QProtobufJsonSerializerImpl::serializeMessageFieldBegin()
324{
325 m_state.emplaceBack(args: std::move(m_result));
326 m_result = {};
327}
328
329void QProtobufJsonSerializerImpl::serializeMessageFieldEnd(const QProtobufMessage *message,
330 const QProtobufFieldInfo &field)
331{
332 QJsonObject store = m_state.takeLast();
333 QString fieldName = field.jsonName().toString();
334 if (field.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) {
335 // Repeated fields are stored in array property
336 // "repeatedField": [{...}, {...}, ...]
337 QJsonArray array = store.value(key: fieldName).toArray();
338 array.append(value: m_result);
339 store.insert(key: fieldName, value: array);
340 } else if (field.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Map)) {
341 // Maps are stored as fields in inner JSON object
342 // "mapField": { "key1": "value1", ... }
343 QJsonObject mapObject = store.value(key: fieldName).toObject();
344 // We don't need to serialize key in general, since all JSON object fields should be
345 // represented as strings, and types that can be map keys have valid string converters.
346 mapObject.insert(key: message->property(propertyName: "key").toString(), value: m_result.value(key: "value"_L1));
347 store.insert(key: fieldName, value: mapObject);
348 } else {
349 store.insert(key: fieldName, value: m_result);
350 }
351 m_result = store;
352}
353
354QProtobufJsonDeserializerImpl::QProtobufJsonDeserializerImpl(QProtobufJsonSerializerPrivate *parent)
355 : m_parent(parent)
356{
357}
358
359QProtobufJsonDeserializerImpl::~QProtobufJsonDeserializerImpl()
360 = default;
361
362void QProtobufJsonDeserializerImpl::reset(QJsonObject obj)
363{
364 clearCachedValue();
365 m_state.clear();
366 if (!obj.isEmpty())
367 m_state.push_back(t: { obj });
368}
369
370void QProtobufJsonDeserializerImpl::setError(QAbstractProtobufSerializer::Error error,
371 QAnyStringView errorString)
372{
373 m_parent->lastError = error;
374 m_parent->lastErrorString = errorString.toString();
375}
376
377bool QProtobufJsonDeserializerImpl::deserializeMessageField(QProtobufMessage *message)
378{
379 if (!message)
380 return true;
381
382 const auto &value = m_state.last().scalarValue;
383 if (!value.isUndefined()) {
384 const auto *metaObject = QtProtobufSerializerHelpers::messageMetaObject(message);
385 if (auto *deserializer = QtProtobufPrivate::findCustomJsonDeserializer(metaType: metaObject
386 ->metaType())) {
387 return deserializer(message, value);
388 }
389 setInvalidFormatError();
390 return false;
391 }
392 return QProtobufDeserializerBase::deserializeMessageField(message);
393}
394
395bool QProtobufJsonDeserializerImpl::deserializeEnum(QVariant &value,
396 const QtProtobufPrivate::QProtobufFieldInfo
397 &fieldInfo)
398{
399 bool ok = false;
400 auto &state = m_state.last();
401 if (fieldInfo.fieldFlags().testFlag(flag: QtProtobufPrivate::FieldFlag::Repeated)) {
402 value = deserializeList<QStringList, QString>(value: state.scalarValue, ok);
403 } else {
404 // It's allowed to pass single enum value as numeric value.
405 // Make the backward value conversion and deserialize enum as QtProtobuf::int64.
406 if (state.scalarValue.isString()) {
407 value = deserializeCommon<QString>(value: state.scalarValue, ok);
408 } else {
409 value = deserializeCommon<QtProtobuf::int64>(value: state.scalarValue, ok);
410 }
411 }
412
413 return ok;
414}
415
416int QProtobufJsonDeserializerImpl::nextFieldIndex(QProtobufMessage *message)
417{
418 const auto *ordering = message->propertyOrdering();
419 const int fieldCount = ordering->fieldCount();
420 if (fieldCount == 0)
421 return -1;
422
423 JsonDeserializerState &state = m_state.last();
424 state.scalarValue = {};
425 while (state.index < fieldCount) {
426 const auto jsonName = ordering->jsonName(index: state.index);
427 const auto keys = state.obj.keys();
428 const auto it = std::find_if(first: keys.constBegin(), last: keys.constEnd(),
429 pred: [&jsonName](const auto &val) {
430 return jsonName == val
431 || jsonName == convertJsonKeyToJsonName(val);
432 });
433
434 if (it == keys.constEnd()) {
435 ++state.index;
436 continue;
437 }
438
439 QtProtobufPrivate::FieldFlags flags = ordering->fieldFlags(index: state.index);
440 QJsonValue val = state.obj.value(key: *it);
441 if (val.isNull()) {
442 ++state.index;
443 continue;
444 }
445
446 int index = state.index;
447 if (flags.testFlags(flags: { QtProtobufPrivate::FieldFlag::Message,
448 QtProtobufPrivate::FieldFlag::Repeated })) {
449 if (!val.isArray()) {
450 setInvalidFormatError();
451 return -1;
452 }
453
454 auto array = val.toArray();
455 if (array.isEmpty()) {
456 ++state.index;
457 state.scalarValue = {};
458 continue;
459 }
460
461 auto nextValue = array.takeAt(i: 0);
462 if (nextValue.isNull()) {
463 setInvalidFormatError();
464 return -1;
465 }
466
467 state.obj.insert(key: *it, value: array);
468 if (nextValue.isObject()) {
469 m_state.push_back(t: { nextValue.toObject() });
470 } else {
471 state.scalarValue = nextValue;
472 }
473 } else if (flags.testFlag(flag: QtProtobufPrivate::FieldFlag::Map)) {
474 if (!val.isObject()) {
475 setInvalidFormatError();
476 return -1;
477 }
478
479 auto mapObject = val.toObject();
480 if (mapObject.isEmpty()) {
481 ++state.index;
482 continue;
483 }
484
485 QString key = mapObject.begin().key();
486 QJsonObject nextObject;
487 nextObject.insert(key: "key"_L1, value: key);
488 nextObject.insert(key: "value"_L1, value: mapObject.take(key));
489 state.obj.insert(key: *it, value: mapObject);
490 m_state.push_back(t: { nextObject });
491 } else if (flags.testFlag(flag: QtProtobufPrivate::FieldFlag::Message)) {
492 if (val.isArray() || val.isUndefined()) {
493 setInvalidFormatError();
494 return -1;
495 }
496
497 if (val.isObject()) {
498 ++state.index;
499 m_state.push_back(t: { val.toObject() });
500 } else {
501 state.scalarValue = val;
502 ++state.index;
503 }
504 } else {
505 state.scalarValue = val;
506 ++state.index;
507 }
508 return index;
509 }
510
511 m_state.pop_back();
512 return -1;
513}
514
515bool QProtobufJsonDeserializerImpl::deserializeScalarField(QVariant &value,
516 const QProtobufFieldInfo &)
517{
518 auto handler = QProtobufJsonSerializerPrivate::handlers.constFind(key: value.userType());
519 if (handler == QProtobufJsonSerializerPrivate::handlers.constEnd()
520 || !handler.value().deserializer) {
521 return false;
522 }
523
524 bool ok = false;
525 value = handler.value().deserializer(m_state.last().scalarValue, ok);
526 if (!ok)
527 setInvalidFormatError();
528 return true;
529}
530
531void QProtobufJsonDeserializerImpl::setUnexpectedEndOfStreamError()
532{
533 setError(error: QAbstractProtobufSerializer::Error::UnexpectedEndOfStream,
534 errorString: QCoreApplication::translate(context: "QtProtobuf", key: "JSON: Unexpected end of stream"));
535}
536
537void QProtobufJsonDeserializerImpl::setInvalidFormatError()
538{
539 setError(error: QAbstractProtobufSerializer::Error::InvalidFormat,
540 errorString: QCoreApplication::translate(context: "QtProtobuf",
541 key: "JSON: One or more fields have invalid format"));
542}
543
544QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {};
545
546QProtobufJsonSerializerPrivate::QProtobufJsonSerializerPrivate() : deserializer(this)
547{
548 [[maybe_unused]] static bool initialized = []() -> bool {
549 handlers[qMetaTypeId<QtProtobuf::int32>()] = createCommonHandler<QtProtobuf::int32>();
550 handlers[qMetaTypeId<QtProtobuf::sfixed32>()] = createCommonHandler<QtProtobuf::sfixed32>();
551 handlers[qMetaTypeId<QtProtobuf::sint32>()] = createCommonHandler<QtProtobuf::sint32>();
552 handlers[qMetaTypeId<QtProtobuf::uint32>()] = createCommonHandler<QtProtobuf::uint32>();
553 handlers[qMetaTypeId<QtProtobuf::fixed32>()] = createCommonHandler<QtProtobuf::fixed32>();
554 handlers[qMetaTypeId<QtProtobuf::sint64>()] = createCommonHandler<QtProtobuf::sint64>();
555 handlers[qMetaTypeId<QtProtobuf::int64>()] = createCommonHandler<QtProtobuf::int64>();
556 handlers[qMetaTypeId<QtProtobuf::sfixed64>()] = createCommonHandler<QtProtobuf::sfixed64>();
557 handlers[qMetaTypeId<QtProtobuf::uint64>()] = createCommonHandler<QtProtobuf::uint64>();
558 handlers[qMetaTypeId<QtProtobuf::fixed64>()] = createCommonHandler<QtProtobuf::fixed64>();
559 handlers[qMetaTypeId<bool>()] = createCommonHandler<bool>();
560 handlers[QMetaType::QString] = createCommonHandler<QString>();
561 handlers[QMetaType::QByteArray] = createCommonHandler<QByteArray>();
562 handlers[QMetaType::Float] = { .serializer: serializeCommon<float>, .deserializer: deserializeCommon<float>,
563 .isPresent: QProtobufJsonSerializerPrivate::isPresent<float> };
564 handlers[QMetaType::Double] = { .serializer: serializeCommon<double>, .deserializer: deserializeCommon<double>,
565 .isPresent: isPresent<double> };
566
567 handlers[qMetaTypeId<QtProtobuf::boolList>()] = createCommonListHandler<
568 QtProtobuf::boolList, bool>();
569 handlers[qMetaTypeId<QtProtobuf::int32List>()] = createCommonListHandler<
570 QtProtobuf::int32List, QtProtobuf::int32>();
571 handlers[qMetaTypeId<QtProtobuf::int64List>()] = createCommonListHandler<
572 QtProtobuf::int64List, QtProtobuf::int64>();
573 handlers[qMetaTypeId<QtProtobuf::sint32List>()] = createCommonListHandler<
574 QtProtobuf::sint32List, QtProtobuf::sint32>();
575 handlers[qMetaTypeId<QtProtobuf::sint64List>()] = createCommonListHandler<
576 QtProtobuf::sint64List, QtProtobuf::sint64>();
577 handlers[qMetaTypeId<QtProtobuf::uint32List>()] = createCommonListHandler<
578 QtProtobuf::uint32List, QtProtobuf::uint32>();
579 handlers[qMetaTypeId<QtProtobuf::uint64List>()] = createCommonListHandler<
580 QtProtobuf::uint64List, QtProtobuf::uint64>();
581 handlers[qMetaTypeId<QtProtobuf::fixed32List>()] = createCommonListHandler<
582 QtProtobuf::fixed32List, QtProtobuf::fixed32>();
583 handlers[qMetaTypeId<QtProtobuf::fixed64List>()] = createCommonListHandler<
584 QtProtobuf::fixed64List, QtProtobuf::fixed64>();
585 handlers[qMetaTypeId<QtProtobuf::sfixed32List>()] = createCommonListHandler<
586 QtProtobuf::sfixed32List, QtProtobuf::sfixed32>();
587 handlers[qMetaTypeId<QtProtobuf::sfixed64List>()] = createCommonListHandler<
588 QtProtobuf::sfixed64List, QtProtobuf::sfixed64>();
589 handlers[qMetaTypeId<QtProtobuf::floatList>()] = createCommonListHandler<
590 QtProtobuf::floatList, float>();
591 handlers[qMetaTypeId<QtProtobuf::doubleList>()] = createCommonListHandler<
592 QtProtobuf::doubleList, double>();
593 handlers[qMetaTypeId<QStringList>()] = createCommonListHandler<QStringList, QString>();
594 handlers[qMetaTypeId<QByteArrayList>()] = createCommonListHandler<QByteArrayList,
595 QByteArray>();
596 return true;
597 }();
598}
599
600void QProtobufJsonSerializerPrivate::clearError()
601{
602 lastError = QAbstractProtobufSerializer::Error::None;
603 lastErrorString.clear();
604}
605
606QProtobufJsonSerializer::QProtobufJsonSerializer() : d_ptr(new QProtobufJsonSerializerPrivate)
607{
608}
609
610QProtobufJsonSerializer::~QProtobufJsonSerializer() = default;
611
612/*!
613 Returns the last deserialization error for the serializer instance.
614 \sa lastErrorString()
615*/
616QAbstractProtobufSerializer::Error QProtobufJsonSerializer::lastError() const
617{
618 return d_ptr->lastError;
619}
620
621/*!
622 Returns the last deserialization error string for the serializer instance.
623 \sa lastError()
624*/
625QString QProtobufJsonSerializer::lastErrorString() const
626{
627 return d_ptr->lastErrorString;
628}
629
630QByteArray QProtobufJsonSerializer::serializeMessage(const QProtobufMessage *message) const
631{
632 d_ptr->clearError();
633 d_ptr->serializer.reset();
634 d_ptr->serializer.serializeMessage(message);
635 auto result = QJsonDocument(d_ptr->serializer.result()).toJson(format: QJsonDocument::Compact);
636 d_ptr->serializer.reset();
637 return result;
638}
639
640bool QProtobufJsonSerializer::deserializeMessage(QProtobufMessage *message,
641 QByteArrayView data) const
642{
643 d_ptr->clearError();
644 QJsonParseError err;
645 auto document = QJsonDocument::fromJson(json: data.toByteArray(), error: &err);
646 if (err.error != QJsonParseError::NoError) {
647 d_ptr->deserializer.setUnexpectedEndOfStreamError();
648 return false;
649 }
650
651 if (!document.isObject()) {
652 d_ptr->deserializer.setInvalidFormatError();
653 return false;
654 }
655
656 if (auto obj = document.object(); !obj.isEmpty()) {
657 d_ptr->deserializer.reset(obj);
658 bool result = d_ptr->deserializer.deserializeMessage(message);
659 d_ptr->deserializer.reset(obj: {});
660 return result;
661 }
662 return true;
663}
664
665bool ProtobufScalarJsonSerializers::validateJsonNumberString(const QString &input)
666{
667 static const QRegularExpression NumberValidator("^-?\\d+$"_L1);
668 return NumberValidator.match(subject: input).hasMatch();
669}
670
671QT_END_NAMESPACE
672

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