qprotobufserializer_p.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. #include <QString>
  26. #include <QByteArray>
  27. #include "qprotobufselfcheckiterator.h"
  28. #include "qtprotobuftypes.h"
  29. #include "qtprotobuflogging.h"
  30. #include "qabstractprotobufserializer.h"
  31. namespace QtProtobuf {
  32. /*!
  33. * \private
  34. *
  35. * \brief The QProtobufSerializerPrivate class
  36. */
  37. class QProtobufSerializerPrivate {
  38. QProtobufSerializerPrivate() = delete;
  39. ~QProtobufSerializerPrivate() = delete;
  40. Q_DISABLE_COPY(QProtobufSerializerPrivate)
  41. QProtobufSerializerPrivate(QProtobufSerializerPrivate &&) = delete;
  42. QProtobufSerializerPrivate &operator =(QProtobufSerializerPrivate &&) = delete;
  43. public:
  44. //###########################################################################
  45. // Serializers
  46. //###########################################################################
  47. template <typename V,
  48. typename std::enable_if_t<std::is_integral<V>::value
  49. && std::is_unsigned<V>::value, int> = 0>
  50. static QByteArray serializeVarintCommon(const V &value) {
  51. qProtoDebug() << __func__ << "value" << value;
  52. V varint = value;
  53. QByteArray result;
  54. while (varint != 0) {
  55. //Put 7 bits to result buffer and mark as "not last" (0b10000000)
  56. result.append((varint & 0b01111111) | 0b10000000);
  57. //Divide values to chunks of 7 bits and move to next chunk
  58. varint >>= 7;
  59. }
  60. if (result.isEmpty()) {
  61. result.append('\0');
  62. }
  63. result.data()[result.size() - 1] &= ~0b10000000;
  64. return result;
  65. }
  66. //---------------Integral and floating point types serializers---------------
  67. /*!
  68. * \brief Serialization of fixed-length primitive types
  69. *
  70. * Natural layout of bits is used: value is encoded in a byte array same way as it is located in memory
  71. *
  72. * \param[in] value Value to serialize
  73. * \param[out] outFieldIndex Index of the value in parent structure (ignored)
  74. * \return Byte array with value encoded
  75. */
  76. template <typename V,
  77. typename std::enable_if_t<std::is_floating_point<V>::value, int> = 0>
  78. static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
  79. qProtoDebug() << __func__ << "value" << value;
  80. //Reserve required number of bytes
  81. QByteArray result(sizeof(V), '\0');
  82. *reinterpret_cast<V *>(result.data()) = value;
  83. return result;
  84. }
  85. /*!
  86. * \brief Serialization of fixed length integral types
  87. *
  88. * \details Natural layout of bits is employed
  89. *
  90. * \param[in] value Value to serialize
  91. * \param[out] outFieldIndex Index of the value in parent structure (ignored)
  92. * \return Byte array with value encoded
  93. */
  94. template <typename V,
  95. typename std::enable_if_t<std::is_same<V, fixed32>::value
  96. || std::is_same<V, fixed64>::value
  97. || std::is_same<V, sfixed32>::value
  98. || std::is_same<V, sfixed64>::value, int> = 0>
  99. static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
  100. qProtoDebug() << __func__ << "value" << value;
  101. //Reserve required number of bytes
  102. QByteArray result(sizeof(V), '\0');
  103. *reinterpret_cast<V *>(result.data()) = value;
  104. return result;
  105. }
  106. /*!
  107. *\brief Serialization of signed integral types
  108. *
  109. * Use <a href="https://developers.google.com/protocol-buffers/docs/encoding">ZigZag encoding</a> first,
  110. * then apply serialization as for unsigned integral types
  111. * \see serializeBasic\<typename V, typename std::enable_if_t\<std::is_integral\<V\>::value && std::is_unsigned\<V\>::value, int\> = 0\>(V, int)
  112. *
  113. * \param[in] value Value to serialize
  114. * \param[out] outFieldIndex Index of the value in parent structure
  115. * \return Byte array with value encoded
  116. */
  117. template <typename V,
  118. typename std::enable_if_t<std::is_integral<V>::value
  119. && std::is_signed<V>::value, int> = 0>
  120. static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
  121. qProtoDebug() << __func__ << "value" << value;
  122. using UV = typename std::make_unsigned<V>::type;
  123. UV uValue = 0;
  124. //Use ZigZag convertion first and apply unsigned variant next
  125. V zigZagValue = (value << 1) ^ (value >> (sizeof(UV) * 8 - 1));
  126. uValue = static_cast<UV>(zigZagValue);
  127. return serializeBasic(uValue, outFieldIndex);
  128. }
  129. template <typename V,
  130. typename std::enable_if_t<std::is_same<V, int32>::value
  131. || std::is_same<V, int64>::value, int> = 0>
  132. static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
  133. qProtoDebug() << __func__ << "value" << value;
  134. using UV = typename std::make_unsigned<V>::type;
  135. return serializeBasic(static_cast<UV>(value), outFieldIndex);
  136. }
  137. /*!
  138. *\brief Serialization of unsigned integral types
  139. *
  140. * Use <a href="https://developers.google.com/protocol-buffers/docs/encoding">Varint encoding</a>:
  141. * "Varints are a method of serializing integers using one or more bytes. Smaller numbers
  142. * [regardless its type] take a smaller number of bytes."
  143. *
  144. * \param[in] value Value to serialize
  145. * \param[out] outFieldIndex Index of the value in parent structure
  146. * \return Byte array with value encoded
  147. */
  148. template <typename V,
  149. typename std::enable_if_t<std::is_integral<V>::value
  150. && std::is_unsigned<V>::value, int> = 0>
  151. static QByteArray serializeBasic(const V &value, int &outFieldIndex) {
  152. qProtoDebug() << __func__ << "value" << value;
  153. V varint = value;
  154. QByteArray result;
  155. while (varint != 0) {
  156. //Put 7 bits to result buffer and mark as "not last" (0b10000000)
  157. result.append((varint & 0b01111111) | 0b10000000);
  158. //Divide values to chunks of 7 bits and move to next chunk
  159. varint >>= 7;
  160. }
  161. // Invalidate field index in case if serialized result is empty
  162. // NOTE: the field will not be sent if its index is equal to NotUsedFieldIndex
  163. if (result.size() == 0) {
  164. outFieldIndex = NotUsedFieldIndex;
  165. } else {
  166. //Mark last chunk as last by clearing last bit
  167. result.data()[result.size() - 1] &= ~0b10000000;
  168. }
  169. return result;
  170. }
  171. //------------------QString and QByteArray types serializers-----------------
  172. template <typename V,
  173. typename std::enable_if_t<std::is_same<V, QString>::value, int> = 0>
  174. static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
  175. return serializeLengthDelimited(value.toUtf8());
  176. }
  177. template <typename V,
  178. typename std::enable_if_t<std::is_same<V, QByteArray>::value, int> = 0>
  179. static QByteArray serializeBasic(const V &value, int &/*outFieldIndex*/) {
  180. return serializeLengthDelimited(value);
  181. }
  182. //--------------------------List types serializers---------------------------
  183. template<typename V,
  184. typename std::enable_if_t<!(std::is_same<V, QString>::value
  185. || std::is_same<V, QByteArray>::value
  186. || std::is_base_of<QObject, V>::value), int> = 0>
  187. static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
  188. qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
  189. if (listValue.count() <= 0) {
  190. outFieldIndex = NotUsedFieldIndex;
  191. return QByteArray();
  192. }
  193. int empty = NotUsedFieldIndex;
  194. QByteArray serializedList;
  195. for (auto &value : listValue) {
  196. serializedList.append(serializeBasic<V>(value, empty));
  197. }
  198. //If internal field type is not LengthDelimited, exact amount of fields to be specified
  199. serializedList = prependLengthDelimitedSize(serializedList);
  200. return serializedList;
  201. }
  202. template<typename V,
  203. typename std::enable_if_t<std::is_same<V, QString>::value, int> = 0>
  204. static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
  205. qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
  206. if (listValue.count() <= 0) {
  207. outFieldIndex = NotUsedFieldIndex;
  208. return QByteArray();
  209. }
  210. QByteArray serializedList;
  211. for (auto &value : listValue) {
  212. serializedList.append(QProtobufSerializerPrivate::encodeHeader(outFieldIndex, LengthDelimited));
  213. serializedList.append(serializeLengthDelimited(value.toUtf8()));
  214. }
  215. outFieldIndex = NotUsedFieldIndex;
  216. return serializedList;
  217. }
  218. template<typename V,
  219. typename std::enable_if_t<std::is_same<V, QByteArray>::value, int> = 0>
  220. static QByteArray serializeListType(const QList<V> &listValue, int &outFieldIndex) {
  221. qProtoDebug() << __func__ << "listValue.count" << listValue.count() << "outFiledIndex" << outFieldIndex;
  222. if (listValue.count() <= 0) {
  223. outFieldIndex = NotUsedFieldIndex;
  224. return QByteArray();
  225. }
  226. QByteArray serializedList;
  227. for (auto &value : listValue) {
  228. serializedList.append(QProtobufSerializerPrivate::encodeHeader(outFieldIndex, LengthDelimited));
  229. serializedList.append(serializeLengthDelimited(value));
  230. }
  231. outFieldIndex = NotUsedFieldIndex;
  232. return serializedList;
  233. }
  234. //###########################################################################
  235. // Deserializers
  236. //###########################################################################
  237. template <typename V,
  238. typename std::enable_if_t<std::is_integral<V>::value
  239. && std::is_unsigned<V>::value, int> = 0>
  240. static V deserializeVarintCommon(QProtobufSelfcheckIterator &it) {
  241. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  242. V value = 0;
  243. int k = 0;
  244. while (true) {
  245. uint64_t byte = static_cast<uint64_t>(*it);
  246. value += (byte & 0b01111111) << k;
  247. k += 7;
  248. if (((*it) & 0b10000000) == 0) {
  249. break;
  250. }
  251. ++it;
  252. }
  253. ++it;
  254. return value;
  255. }
  256. //-------------Integral and floating point types deserializers---------------
  257. template <typename V,
  258. typename std::enable_if_t<std::is_floating_point<V>::value
  259. || std::is_same<V, fixed32>::value
  260. || std::is_same<V, fixed64>::value
  261. || std::is_same<V, sfixed32>::value
  262. || std::is_same<V, sfixed64>::value, int> = 0>
  263. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  264. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  265. QVariant newPropertyValue(QVariant::fromValue(*(V *)((QByteArray::const_iterator&)it)));
  266. it += sizeof(V);
  267. return newPropertyValue;
  268. }
  269. template <typename V,
  270. typename std::enable_if_t<std::is_integral<V>::value
  271. && std::is_unsigned<V>::value, int> = 0>
  272. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  273. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  274. return QVariant::fromValue(deserializeVarintCommon<V>(it));
  275. }
  276. template <typename V,
  277. typename std::enable_if_t<std::is_integral<V>::value
  278. && std::is_signed<V>::value,int> = 0>
  279. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  280. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  281. using UV = typename std::make_unsigned<V>::type;
  282. UV unsignedValue = deserializeVarintCommon<UV>(it);
  283. V value = (unsignedValue >> 1) ^ (-1 * (unsignedValue & 1));
  284. return QVariant::fromValue<V>(value);
  285. }
  286. template <typename V,
  287. typename std::enable_if_t<std::is_same<int32, V>::value
  288. || std::is_same<int64, V>::value, int> = 0>
  289. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  290. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  291. using UV = typename std::make_unsigned<V>::type;
  292. UV unsignedValue = deserializeVarintCommon<UV>(it);
  293. V value = static_cast<V>(unsignedValue);
  294. return QVariant::fromValue(value);
  295. }
  296. //-----------------QString and QByteArray types deserializers----------------
  297. template <typename V,
  298. typename std::enable_if_t<std::is_same<QByteArray, V>::value, int> = 0>
  299. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  300. return QVariant::fromValue(deserializeLengthDelimited(it));
  301. }
  302. template <typename V,
  303. typename std::enable_if_t<std::is_same<QString, V>::value, int> = 0>
  304. static QVariant deserializeBasic(QProtobufSelfcheckIterator &it) {
  305. return QVariant::fromValue(QString::fromUtf8(deserializeLengthDelimited(it)));
  306. }
  307. //-------------------------List types deserializers--------------------------
  308. template <typename V,
  309. typename std::enable_if_t<std::is_same<V, QByteArray>::value, int> = 0>
  310. static void deserializeList(QProtobufSelfcheckIterator &it, QVariant &previous) {
  311. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  312. QByteArrayList list = previous.value<QByteArrayList>();
  313. list.append(deserializeLengthDelimited(it));
  314. previous.setValue(list);
  315. }
  316. template <typename V,
  317. typename std::enable_if_t<std::is_same<V, QString>::value, int> = 0>
  318. static void deserializeList(QProtobufSelfcheckIterator &it, QVariant &previous) {
  319. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  320. QStringList list = previous.value<QStringList>();
  321. QByteArray value = deserializeLengthDelimited(it);
  322. list.append(QString::fromUtf8(value));
  323. previous.setValue(list);
  324. }
  325. template <typename V,
  326. typename std::enable_if_t<!(std::is_same<V, QString>::value
  327. || std::is_same<V, QByteArray>::value
  328. || std::is_base_of<QObject, V>::value), int> = 0>
  329. static void deserializeList(QProtobufSelfcheckIterator &it, QVariant &previous) {
  330. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  331. QList<V> out;
  332. unsigned int count = deserializeVarintCommon<uint32>(it);
  333. QProtobufSelfcheckIterator lastVarint = it + count;
  334. while (it != lastVarint) {
  335. QVariant variant = deserializeBasic<V>(it);
  336. out.append(variant.value<V>());
  337. }
  338. previous.setValue(out);
  339. }
  340. //###########################################################################
  341. // Common functions
  342. //###########################################################################
  343. static QByteArray deserializeLengthDelimited(QProtobufSelfcheckIterator &it) {
  344. qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
  345. unsigned int length = deserializeVarintCommon<uint32>(it);
  346. QByteArray result((QByteArray::const_iterator&)it, length); //TODO: it's possible to void buffeer copying by setupimg new "end of QByteArray";
  347. it += length;
  348. return result;
  349. }
  350. static QByteArray serializeLengthDelimited(const QByteArray &data) {
  351. qProtoDebug() << __func__ << "data.size" << data.size() << "data" << data.toHex();
  352. QByteArray result(data);
  353. //Varint serialize field size and apply result as starting point
  354. result = prependLengthDelimitedSize(result);
  355. return result;
  356. }
  357. static bool decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex, WireTypes &wireType);
  358. static QByteArray encodeHeader(int fieldIndex, WireTypes wireType);
  359. /*!
  360. * \brief Gets length of a byte-array and prepends to it its serialized length value
  361. * using the appropriate serialization algorithm
  362. *
  363. *
  364. * \param[in, out] serializedList Byte-array to be prepended
  365. */
  366. static QByteArray prependLengthDelimitedSize(const QByteArray &data)
  367. {
  368. return serializeVarintCommon<uint32_t>(data.size()) + data;
  369. }
  370. // this set of 3 methods is used to skip bytes corresponding to an unexpected property
  371. // in a serialized message met while the message being deserialized
  372. static int skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, WireTypes type);
  373. static void deserializeMapField(QVariant &value, QProtobufSelfcheckIterator &it);
  374. template <typename T,
  375. typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
  376. static void wrapSerializer(QAbstractProtobufSerializer::SerializerRegistry &handlers, const std::function<QByteArray(const T &, int &)> &s, const std::function<QVariant(QProtobufSelfcheckIterator &)> &d, WireTypes type)
  377. {
  378. handlers[qMetaTypeId<T>()] = {
  379. [s](const QVariant &value, int &fieldIndex) {
  380. return s(value.value<T>(), fieldIndex);
  381. },
  382. [d](QProtobufSelfcheckIterator &it, QVariant & value){
  383. value = d(it);
  384. },
  385. type
  386. };
  387. }
  388. template <typename T,
  389. typename std::enable_if_t<!std::is_base_of<QObject, T>::value, int> = 0>
  390. static void wrapSerializer(QAbstractProtobufSerializer::SerializerRegistry &handlers, const std::function<QByteArray(const T &, int &)> &s, const std::function<void(QProtobufSelfcheckIterator &it, QVariant & value)> &d, WireTypes type)
  391. {
  392. handlers[qMetaTypeId<T>()] = {
  393. [s](const QVariant &value, int &fieldIndex) {
  394. return s(value.value<T>(), fieldIndex);
  395. },
  396. d,
  397. type
  398. };
  399. }
  400. protected:
  401. static void skipVarint(QProtobufSelfcheckIterator &it);
  402. static void skipLengthDelimited(QProtobufSelfcheckIterator &it);
  403. };
  404. //###########################################################################
  405. // Common functions
  406. //###########################################################################
  407. /*! \brief Encode a property field index and its type into output bytes
  408. *
  409. * \details
  410. * Header byte
  411. * Meaning | Field index | Type
  412. * ---------- | ------------- | --------
  413. * bit number | 7 6 5 4 3 | 2 1 0
  414. * \param fieldIndex The index of a property in parent object
  415. * \param wireType Serialization type used for the property with index @p fieldIndex
  416. *
  417. * \return Varint encoded fieldIndex and wireType
  418. */
  419. inline QByteArray QProtobufSerializerPrivate::encodeHeader(int fieldIndex, WireTypes wireType)
  420. {
  421. uint32_t header = (fieldIndex << 3) | wireType;
  422. return serializeVarintCommon<uint32_t>(header);
  423. }
  424. /*! \brief Decode a property field index and its serialization type from input bytes
  425. *
  426. * \param[in] Iterator that points to header with encoded field index and serialization type
  427. * \param[out] fieldIndex Decoded index of a property in parent object
  428. * \param[out] wireType Decoded serialization type used for the property with index @p fieldIndex
  429. *
  430. * \return true if both decoded wireType and fieldIndex have "allowed" values and false, otherwise
  431. */
  432. inline bool QProtobufSerializerPrivate::decodeHeader(QProtobufSelfcheckIterator &it, int &fieldIndex, WireTypes &wireType)
  433. {
  434. uint32_t header = deserializeVarintCommon<uint32_t>(it);
  435. wireType = static_cast<WireTypes>(header & 0b00000111);
  436. fieldIndex = header >> 3;
  437. constexpr int maxFieldIndex = (1 << 29) - 1;
  438. return fieldIndex <= maxFieldIndex && fieldIndex > 0 && (wireType == Varint
  439. || wireType == Fixed64
  440. || wireType == Fixed32
  441. || wireType == LengthDelimited);
  442. }
  443. }