QtProtobuf  0.6
Protobuf plugin to generate Qt classes
qprotobufserializer_p.h
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Viktor Kopp <vifactor@gmail.com>
5  *
6  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy of this
9  * software and associated documentation files (the "Software"), to deal in the Software
10  * without restriction, including without limitation the rights to use, copy, modify,
11  * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
12  * to permit persons to whom the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in all copies
16  * or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
20  * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
21  * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <QString>
27 #include <QByteArray>
28 
29 #include "qprotobufselfcheckiterator.h"
30 #include "qtprotobuftypes.h"
31 #include "qtprotobuflogging.h"
32 #include "qabstractprotobufserializer.h"
33 
34 namespace QtProtobuf {
35 
41 class QProtobufSerializer;
43 class QProtobufSerializerPrivate final
44 {
45  Q_DISABLE_COPY_MOVE(QProtobufSerializerPrivate)
46 public:
47 
51  using Serializer = QByteArray(*)(const QVariant &, int &);
55  using Deserializer = void(*)(QProtobufSelfcheckIterator &, QVariant &);
56 
61  struct SerializationHandlers {
62  Serializer serializer;
63  Deserializer deserializer;
64  WireTypes type;
65  };
66 
67  using SerializerRegistry = std::unordered_map<int/*metatypeid*/, SerializationHandlers>;
68 
69  QProtobufSerializerPrivate(QProtobufSerializer *q);
70  ~QProtobufSerializerPrivate() = default;
71  //###########################################################################
72  // Serializers
73  //###########################################################################
74 
75  template <typename V,
76  typename std::enable_if_t<std::is_integral<V>::value
77  && std::is_unsigned<V>::value, int> = 0>
78  static QByteArray serializeVarintCommon(const V &value) {
79  qProtoDebug() << __func__ << "value" << value;
80  V varint = value;
81  QByteArray result;
82 
83  while (varint != 0) {
84  //Put 7 bits to result buffer and mark as "not last" (0b10000000)
85  result.append((varint & 0b01111111) | 0b10000000);
86  //Divide values to chunks of 7 bits and move to next chunk
87  varint >>= 7;
88  }
89 
90  if (result.isEmpty()) {
91  result.append('\0');
92  }
93 
94  result.data()[result.size() - 1] &= ~0b10000000;
95  return result;
96  }
97 
98  //---------------Integral and floating point types serializers---------------
108  template <typename V,
109  typename std::enable_if_t<std::is_floating_point<V>::value, int> = 0>
110  static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
111  qProtoDebug() << __func__ << "value" << value;
112 
113  //Reserve required number of bytes
114  QByteArray result(sizeof(V), '\0');
115  *reinterpret_cast<V *>(result.data()) = value;
116  return result;
117  }
118 
128  template <typename V,
129  typename std::enable_if_t<std::is_same<V, fixed32>::value
130  || std::is_same<V, fixed64>::value
131  || std::is_same<V, sfixed32>::value
132  || std::is_same<V, sfixed64>::value, int> = 0>
133  static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
134  qProtoDebug() << __func__ << "value" << value;
135 
136  //Reserve required number of bytes
137  QByteArray result(sizeof(V), '\0');
138  *reinterpret_cast<V *>(result.data()) = value;
139  return result;
140  }
141 
153  template <typename V,
154  typename std::enable_if_t<std::is_integral<V>::value
155  && std::is_signed<V>::value, int> = 0>
156  static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
157  qProtoDebug() << __func__ << "value" << value;
158  using UV = typename std::make_unsigned<V>::type;
159  UV uValue = 0;
160 
161  //Use ZigZag convertion first and apply unsigned variant next
162  V zigZagValue = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
163  uValue = static_cast<UV>(zigZagValue);
164  return serializeBasic(uValue, outFieldIndex);
165  }
166 
167  template <typename V,
168  typename std::enable_if_t<std::is_same<V, int32>::value
169  || std::is_same<V, int64>::value, int> = 0>
170  static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
171  qProtoDebug() << __func__ << "value" << value;
172  using UV = typename std::make_unsigned<V>::type;
173  return serializeBasic(static_cast<UV>(value), outFieldIndex);
174  }
175 
187  template <typename V,
188  typename std::enable_if_t<std::is_integral<V>::value
189  && std::is_unsigned<V>::value, int> = 0>
190  static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
191  qProtoDebug() << __func__ << "value" << value;
192  V varint = value;
193  QByteArray result;
194 
195  while (varint != 0) {
196  //Put 7 bits to result buffer and mark as "not last" (0b10000000)
197  result.append((varint & 0b01111111) | 0b10000000);
198  //Divide values to chunks of 7 bits and move to next chunk
199  varint >>= 7;
200  }
201 
202  // Invalidate field index in case if serialized result is empty
203  // NOTE: the field will not be sent if its index is equal to NotUsedFieldIndex
204  if (result.size() == 0) {
205  outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
206  } else {
207  //Mark last chunk as last by clearing last bit
208  result.data()[result.size() - 1] &= ~0b10000000;
209  }
210  return result;
211  }
212 
213  //------------------QString and QByteArray types serializers-----------------
214  template <typename V,
215  typename std::enable_if_t<std::is_same<V, QString>::value, int> = 0>
216  static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
217  return serializeLengthDelimited(value.toUtf8());
218  }
219 
220  template <typename V,
221  typename std::enable_if_t<std::is_same<V, QByteArray>::value, int> = 0>
222  static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
223  return serializeLengthDelimited(value);
224  }
225 
226  //--------------------------List types serializers---------------------------
227  template<typename V,
228  typename std::enable_if_t<!(std::is_same<V, QString>::value
229  || std::is_base_of<QObject, V>::value), int> = 0>
230  static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
231  qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
232 
233  if (listValue.count() <= 0) {
234  outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
235  return QByteArray();
236  }
237 
238  int empty = QtProtobufPrivate::NotUsedFieldIndex;
239  QByteArray serializedList;
240  for (auto &value : listValue) {
241  QByteArray element = serializeBasic<V>(value, empty);
242  if (element.isEmpty()) {
243  element.append('\0');
244  }
245  serializedList.append(element);
246  }
247  //If internal field type is not LengthDelimited, exact amount of fields to be specified
248  serializedList = prependLengthDelimitedSize(serializedList);
249  return serializedList;
250  }
251 
252  template<typename V,
253  typename std::enable_if_t<std::is_same<V, QString>::value, int> = 0>
254  static QByteArray serializeListType(const QStringList &listValue, int &outFieldIndex) {
255  qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
256 
257  if (listValue.count() <= 0) {
258  outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
259  return QByteArray();
260  }
261 
262  QByteArray serializedList;
263  for (auto &value : listValue) {
264  serializedList.append(QProtobufSerializerPrivate::encodeHeader(outFieldIndex, LengthDelimited));
265  serializedList.append(serializeLengthDelimited(value.toUtf8()));
266  }
267 
268  outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
269  return serializedList;
270  }
271 
272  //###########################################################################
273  // Deserializers
274  //###########################################################################
275  template <typename V,
276  typename std::enable_if_t<std::is_integral<V>::value
277  && std::is_unsigned<V>::value, int> = 0>
278  static V deserializeVarintCommon(QProtobufSelfcheckIterator &it) {
279  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
280 
281  V value = 0;
282  int k = 0;
283  while (true) {
284  uint64_t byte = static_cast<uint64_t>(*it);
285  value += (byte & 0b01111111) << k;
286  k += 7;
287  if (((*it) & 0b10000000) == 0) {
288  break;
289  }
290  ++it;
291  }
292  ++it;
293  return value;
294  }
295 
296  //-------------Integral and floating point types deserializers---------------
297  template <typename V,
298  typename std::enable_if_t<std::is_floating_point<V>::value
299  || std::is_same<V, fixed32>::value
300  || std::is_same<V, fixed64>::value
301  || std::is_same<V, sfixed32>::value
302  || std::is_same<V, sfixed64>::value, int> = 0>
303  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
304  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
305 
306  variantValue = QVariant::fromValue(*(V *)((QByteArray::const_iterator&)it));
307  it += sizeof(V);
308  }
309 
310  template <typename V,
311  typename std::enable_if_t<std::is_integral<V>::value
312  && std::is_unsigned<V>::value, int> = 0>
313  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
314  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
315 
316  variantValue = QVariant::fromValue(deserializeVarintCommon<V>(it));
317  }
318 
319  template <typename V,
320  typename std::enable_if_t<std::is_integral<V>::value
321  && std::is_signed<V>::value,int> = 0>
322  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
323  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
324  using UV = typename std::make_unsigned<V>::type;
325  UV unsignedValue = deserializeVarintCommon<UV>(it);
326  V value = (unsignedValue >> 1) ^ (-1 * (unsignedValue & 1));
327  variantValue = QVariant::fromValue<V>(value);
328  }
329 
330  template <typename V,
331  typename std::enable_if_t<std::is_same<int32, V>::value
332  || std::is_same<int64, V>::value, int> = 0>
333  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
334  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
335  using UV = typename std::make_unsigned<V>::type;
336  UV unsignedValue = deserializeVarintCommon<UV>(it);
337  V value = static_cast<V>(unsignedValue);
338  variantValue = QVariant::fromValue(value);
339  }
340 
341  //-----------------QString and QByteArray types deserializers----------------
342  template <typename V,
343  typename std::enable_if_t<std::is_same<QByteArray, V>::value, int> = 0>
344  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
345  variantValue = QVariant::fromValue(deserializeLengthDelimited(it));
346  }
347 
348  template <typename V,
349  typename std::enable_if_t<std::is_same<QString, V>::value, int> = 0>
350  static void deserializeBasic(QProtobufSelfcheckIterator &it, QVariant &variantValue) {
351  variantValue = QVariant::fromValue(QString::fromUtf8(deserializeLengthDelimited(it)));
352  }
353 
354  //-------------------------List types deserializers--------------------------
355  template <typename V,
356  typename std::enable_if_t<!std::is_base_of<QObject, V>::value, int> = 0>
357  static void deserializeList(QProtobufSelfcheckIterator &it, QVariant &previousValue) {
358  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
359 
360  QList<V> out;
361  unsigned int count = deserializeVarintCommon<uint32>(it);
362  QProtobufSelfcheckIterator lastVarint = it + count;
363  while (it != lastVarint) {
364  QVariant variantValue;
365  deserializeBasic<V>(it, variantValue);
366  out.append(variantValue.value<V>());
367  }
368  previousValue.setValue(out);
369  }
370 
371  //###########################################################################
372  // Common functions
373  //###########################################################################
374  static QByteArray deserializeLengthDelimited(QProtobufSelfcheckIterator &it) {
375  qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
376 
377  unsigned int length = deserializeVarintCommon<uint32>(it);
378  QByteArray result((QByteArray::const_iterator&)it, length); //TODO: it's possible to avoid buffer copying by setuping new "end of QByteArray";
379  it += length;
380  return result;
381  }
382 
383  static QByteArray serializeLengthDelimited(const QByteArray &data) {
384  qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data.toHex();
385  QByteArray result(data);
386  //Varint serialize field size and apply result as starting point
387  result = prependLengthDelimitedSize(result);
388  return result;
389  }
390 
391  static bool decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex, WireTypes &wireType);
392  static QByteArray encodeHeader(int fieldIndex, WireTypes wireType);
393 
401  static QByteArray prependLengthDelimitedSize(const QByteArray &data)
402  {
403  return serializeVarintCommon<uint32_t>(data.size()) + data;
404  }
405 
406  template <typename T,
407  QByteArray(*s)(const T &, int &)>
408  static QByteArray serializeWrapper(const QVariant &variantValue, int &fieldIndex) {
409  if (variantValue.isNull()) {
410  fieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
411  return QByteArray();
412  }
413  const T& value = *(static_cast<const T *>(variantValue.data()));
414  return s(value, fieldIndex);
415  }
416 
417  template <typename T, QByteArray(*s)(const T &, int &), Deserializer d, WireTypes type,
418  typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
419  static void wrapSerializer() {
420  handlers[qMetaTypeId<T>()] = {
421  serializeWrapper<T, s>,
422  d,
423  type
424  };
425  }
426 
427  template <typename T, typename S, QByteArray(*s)(const S &, int &), Deserializer d, WireTypes type,
428  typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
429  static void wrapSerializer() {
430  handlers[qMetaTypeId<T>()] = {
431  serializeWrapper<S, s>,
432  d,
433  type
434  };
435  }
436 
437  // this set of 3 methods is used to skip bytes corresponding to an unexpected property
438  // in a serialized message met while the message being deserialized
439  static int skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, WireTypes type);
440  static void skipVarint(QProtobufSelfcheckIterator &it);
441  static void skipLengthDelimited(QProtobufSelfcheckIterator &it);
442 
443  QByteArray serializeProperty(const QVariant &propertyValue, const QProtobufMetaProperty &metaProperty);
444  void deserializeProperty(QObject *object, const QProtobufMetaObject &metaObject, QProtobufSelfcheckIterator &it);
445 
446  void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it);
447 private:
448  static SerializerRegistry handlers;
449  QProtobufSerializer *q_ptr;
450 };
451 
452 //###########################################################################
453 // Common functions
454 //###########################################################################
455 
468 inline QByteArray QProtobufSerializerPrivate::encodeHeader(int fieldIndex, WireTypes wireType)
469 {
470  uint32_t header = (fieldIndex << 3) | wireType;
471  return serializeVarintCommon<uint32_t>(header);
472 }
473 
482 inline bool QProtobufSerializerPrivate::decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex, WireTypes &wireType)
483 {
484  uint32_t header = deserializeVarintCommon<uint32_t>(it);
485  wireType = static_cast<WireTypes>(header & 0b00000111);
486  fieldIndex = header >> 3;
487 
488  constexpr int maxFieldIndex = (1 << 29) - 1;
489  return fieldIndex <= maxFieldIndex && fieldIndex > 0 && (wireType == Varint
490  || wireType == Fixed64
491  || wireType == Fixed32
492  || wireType == LengthDelimited);
493 }
494 
495 }
WireTypes
The WireTypes enumeration reflects protobuf default wiretypes.
Definition: qtprotobuftypes.h:47
@ Varint
int32, int64, uint32, uint64, sint32, sint64, bool, enum
Definition: qtprotobuftypes.h:49
@ Fixed32
fixed32, sfixed32, float
Definition: qtprotobuftypes.h:54
@ Fixed64
fixed64, sfixed64, double
Definition: qtprotobuftypes.h:50
@ LengthDelimited
string, bytes, embedded messages, packed repeated fields
Definition: qtprotobuftypes.h:51