protobufobject.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2019 Alexey Edelev <semlanik@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 "protobufobject.h"
  26. using namespace qtprotobuf;
  27. ProtobufObjectPrivate::SerializerRegistry ProtobufObjectPrivate::serializers = {};
  28. namespace {
  29. static const char *sint32TypeNameP = "qtprotobuf::sint32";
  30. static const char *sint32TypeName = "sint32";
  31. static const char *sint64TypeNameP = "qtprotobuf::sint64";
  32. static const char *sint64TypeName = "sint64";
  33. static const char *sint32ListTypeNameP = "qtprotobuf::sint32List";
  34. static const char *sint32ListTypeName = "sint32List";
  35. static const char *sint64ListTypeNameP = "qtprotobuf::sint64List";
  36. static const char *sint64ListTypeName = "sint64List";
  37. static const char *fint32TypeNameP = "qtprotobuf::fint32";
  38. static const char *fint32TypeName = "fint32";
  39. static const char *fint64TypeNameP = "qtprotobuf::fint64";
  40. static const char *fint64TypeName = "fint64";
  41. static const char *sfint32TypeNameP = "qtprotobuf::sfint32";
  42. static const char *sfint32TypeName = "sfint32";
  43. static const char *sfint64TypeNameP = "qtprotobuf::sfint64";
  44. static const char *sfint64TypeName = "sfint64";
  45. static const char *fint32ListTypeNameP = "qtprotobuf::fint32List";
  46. static const char *fint32ListTypeName = "fint32List";
  47. static const char *fint64ListTypeNameP = "qtprotobuf::fint64List";
  48. static const char *fint64ListTypeName = "fint64List";
  49. static const char *sfint32ListTypeNameP = "qtprotobuf::sfint32List";
  50. static const char *sfint32ListTypeName = "sfint32List";
  51. static const char *sfint64ListTypeNameP = "qtprotobuf::sfint64List";
  52. static const char *sfint64ListTypeName = "sfint64List";
  53. }
  54. QByteArray ProtobufObjectPrivate::serializeValue(const QVariant &propertyValue, int fieldIndex, const QMetaProperty &metaProperty) const
  55. {
  56. QLatin1Literal typeName(metaProperty.typeName());
  57. QByteArray result;
  58. WireTypes type = UnknownWireType;
  59. qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex << "typeName"
  60. << typeName << static_cast<QMetaType::Type>(propertyValue.type());
  61. switch (static_cast<QMetaType::Type>(propertyValue.type())) {
  62. case QMetaType::Int:
  63. type = Varint;
  64. if (typeName == sint32TypeNameP
  65. || typeName == sint32TypeName) {
  66. result.append(serializeVarintZigZag(propertyValue.toInt()));
  67. } else if (typeName == sfint32TypeNameP
  68. || typeName == sfint32TypeName) {
  69. type = Fixed32;
  70. result.append(serializeFixed(propertyValue.toInt()));
  71. } else {
  72. result.append(serializeVarint(propertyValue.toLongLong()));
  73. }
  74. if (0 == result.size()) {
  75. fieldIndex = NotUsedFieldIndex;
  76. }
  77. break;
  78. case QMetaType::LongLong:
  79. type = Varint;
  80. if (typeName == sint64TypeNameP
  81. || typeName == sint64TypeName) {
  82. result.append(serializeVarintZigZag(propertyValue.toLongLong()));
  83. } else if (typeName == sfint64TypeNameP
  84. || typeName == sfint64TypeName) {
  85. type = Fixed64;
  86. result.append(serializeFixed(propertyValue.toLongLong()));
  87. } else {
  88. result.append(serializeVarint(propertyValue.toLongLong()));
  89. }
  90. if (0 == result.size()) {
  91. fieldIndex = NotUsedFieldIndex;
  92. }
  93. break;
  94. case QMetaType::Float:
  95. type = Fixed32;
  96. result.append(serializeFixed(propertyValue.toFloat()));
  97. break;
  98. case QMetaType::Double:
  99. type = Fixed64;
  100. result.append(serializeFixed(propertyValue.toDouble()));
  101. break;
  102. case QMetaType::QString:
  103. type = LengthDelimited;
  104. result.append(serializeLengthDelimited(propertyValue.toString()));
  105. break;
  106. case QMetaType::QByteArray:
  107. type = LengthDelimited;
  108. result.append(serializeLengthDelimited(propertyValue.toByteArray()));
  109. break;
  110. case QMetaType::QStringList:
  111. type = LengthDelimited;
  112. result.append(serializeListType(propertyValue.toStringList(), fieldIndex));
  113. break;
  114. case QMetaType::QByteArrayList:
  115. type = LengthDelimited;
  116. result.append(serializeListType(propertyValue.value<QByteArrayList>(), fieldIndex));
  117. break;
  118. case QMetaType::User:
  119. if(metaProperty.isEnumType()) {
  120. type = Varint;
  121. result.append(serializeVarint(propertyValue.toLongLong()));
  122. } else {
  123. type = LengthDelimited;
  124. result.append(serializeUserType(propertyValue, fieldIndex, typeName));
  125. }
  126. break;
  127. case QMetaType::UInt:
  128. if (typeName == fint32TypeNameP
  129. || typeName == fint32TypeName) {
  130. type = Fixed32;
  131. result.append(serializeFixed(propertyValue.toUInt()));
  132. } else {
  133. type = Varint;
  134. result.append(serializeVarint(propertyValue.toUInt()));
  135. }
  136. if (0 == result.size()) {
  137. fieldIndex = NotUsedFieldIndex;
  138. }
  139. break;
  140. case QMetaType::ULongLong:
  141. if (typeName == fint64TypeNameP
  142. || typeName == fint64TypeName) {
  143. type = Fixed64;
  144. result.append(serializeFixed(propertyValue.toULongLong()));
  145. } else {
  146. type = Varint;
  147. result.append(serializeVarint(propertyValue.toULongLong()));
  148. }
  149. if (0 == result.size()) {
  150. fieldIndex = NotUsedFieldIndex;
  151. }
  152. break;
  153. case QMetaType::Bool:
  154. type = Varint;
  155. result.append(serializeVarint(propertyValue.toUInt()));
  156. if (0 == result.size()) {
  157. fieldIndex = NotUsedFieldIndex;
  158. }
  159. break;
  160. default:
  161. Q_ASSERT_X(false, staticMetaObject.className(), "Serialization of unknown type is impossible");
  162. }
  163. if (fieldIndex != NotUsedFieldIndex
  164. && type != UnknownWireType) {
  165. result.prepend(encodeHeaderByte(fieldIndex, type));
  166. }
  167. return result;
  168. }
  169. QByteArray ProtobufObjectPrivate::serializeUserType(const QVariant &propertyValue, int &fieldIndex, const QLatin1Literal &typeName) const
  170. {
  171. qProtoDebug() << __func__ << "propertyValue" << propertyValue << "fieldIndex" << fieldIndex;
  172. int userType = propertyValue.userType();
  173. //First looking type serializer in registred serializers
  174. auto it = serializers.find(userType);
  175. if (it != std::end(serializers)) {
  176. return (it->second).serializer(this, propertyValue, fieldIndex);
  177. }
  178. //Check if it's special list
  179. if (userType == qMetaTypeId<int32List>()) {
  180. if (typeName == sint32ListTypeNameP
  181. || typeName == sint32ListTypeName) {
  182. return serializeListTypeZigZag(propertyValue.value<sint32List>(), fieldIndex);
  183. }
  184. if (typeName == sfint32ListTypeNameP
  185. || typeName == sfint32ListTypeName) {
  186. return serializeFixedListType(propertyValue.value<sfint32List>(), fieldIndex);
  187. }
  188. return serializeListType(propertyValue.value<int32List>(), fieldIndex);
  189. }
  190. if (userType == qMetaTypeId<uint32List>()) {
  191. if (typeName == fint32ListTypeNameP
  192. || typeName == fint32ListTypeName) {
  193. return serializeFixedListType(propertyValue.value<fint32List>(), fieldIndex);
  194. }
  195. return serializeListType(propertyValue.value<uint32List>(), fieldIndex);
  196. }
  197. if (userType == qMetaTypeId<int64List>()) {
  198. if (typeName == sint64ListTypeNameP
  199. || typeName == sint64ListTypeName) {
  200. return serializeListTypeZigZag(propertyValue.value<sint64List>(), fieldIndex);
  201. }
  202. if (typeName == sfint64ListTypeNameP
  203. || typeName == sfint64ListTypeName) {
  204. return serializeFixedListType(propertyValue.value<sfint64List>(), fieldIndex);
  205. }
  206. return serializeListType(propertyValue.value<int64List>(), fieldIndex);
  207. }
  208. if (userType == qMetaTypeId<uint64List>()) {
  209. if (typeName == fint64ListTypeNameP
  210. || typeName == fint64ListTypeName) {
  211. return serializeFixedListType(propertyValue.value<fint64List>(), fieldIndex);
  212. }
  213. return serializeListType(propertyValue.value<uint64List>(), fieldIndex);
  214. }
  215. if (userType == qMetaTypeId<FloatList>()) {
  216. return serializeFixedListType(propertyValue.value<FloatList>(), fieldIndex);
  217. }
  218. if (userType == qMetaTypeId<DoubleList>()) {
  219. return serializeFixedListType(propertyValue.value<DoubleList>(), fieldIndex);
  220. }
  221. return serializers[userType].serializer(this, propertyValue, fieldIndex);
  222. }
  223. void ProtobufObjectPrivate::deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
  224. {
  225. QLatin1Literal typeName(metaProperty.typeName());
  226. qProtoDebug() << __func__ << " wireType: " << wireType << " metaProperty: " << typeName << "currentByte:" << QString::number((*it), 16);
  227. QVariant newPropertyValue;
  228. int type = metaProperty.type();
  229. switch (type) {
  230. case QMetaType::UInt:
  231. if (wireType == Fixed32) {
  232. newPropertyValue = deserializeFixed<fint32>(it);
  233. } else {
  234. newPropertyValue = deserializeVarint<uint32>(it);
  235. }
  236. break;
  237. case QMetaType::ULongLong:
  238. if (wireType == Fixed64) {
  239. newPropertyValue = deserializeFixed<fint64>(it);
  240. } else {
  241. newPropertyValue = deserializeVarint<uint64>(it);
  242. }
  243. break;
  244. case QMetaType::Float:
  245. newPropertyValue = deserializeFixed<float>(it);
  246. break;
  247. case QMetaType::Double:
  248. newPropertyValue = deserializeFixed<double>(it);
  249. break;
  250. case QMetaType::Int:
  251. if (wireType == Fixed32) {
  252. newPropertyValue = deserializeFixed<sfint32>(it);
  253. } else if (typeName == sint32TypeNameP
  254. || typeName == sint32TypeName) {
  255. newPropertyValue = deserializeVarintZigZag<sint32>(it);
  256. } else {
  257. newPropertyValue = deserializeVarint<int64>(it);
  258. }
  259. break;
  260. case QMetaType::LongLong:
  261. if (wireType == Fixed64) {
  262. newPropertyValue = deserializeFixed<sfint64>(it);
  263. } else if (typeName == sint64TypeNameP
  264. || typeName == sint64TypeName) {
  265. newPropertyValue = deserializeVarintZigZag<sint64>(it);
  266. } else {
  267. newPropertyValue = deserializeVarint<int64>(it);
  268. }
  269. break;
  270. case QMetaType::QString:
  271. newPropertyValue = QString::fromUtf8(deserializeLengthDelimited(it));
  272. break;
  273. case QMetaType::QByteArray:
  274. newPropertyValue = deserializeLengthDelimited(it);
  275. break;
  276. case QMetaType::User:
  277. if (metaProperty.isEnumType()) {
  278. newPropertyValue = deserializeVarint<int32>(it);
  279. } else {
  280. newPropertyValue = metaProperty.read(this);
  281. deserializeUserType(metaProperty, it, newPropertyValue);
  282. }
  283. break;
  284. case QMetaType::QByteArrayList: {
  285. QByteArrayList currentValue = metaProperty.read(this).value<QByteArrayList>();
  286. currentValue.append(deserializeLengthDelimited(it));
  287. metaProperty.write(this, QVariant::fromValue<QByteArrayList>(currentValue));
  288. }
  289. return;
  290. case QMetaType::QStringList: {
  291. QStringList currentValue = metaProperty.read(this).value<QStringList>();
  292. currentValue.append(QString::fromUtf8(deserializeLengthDelimited(it)));
  293. metaProperty.write(this, currentValue);
  294. }
  295. return;
  296. case QMetaType::Bool:
  297. newPropertyValue = deserializeVarint<uint32>(it);
  298. break;
  299. default:
  300. break;
  301. }
  302. metaProperty.write(this, newPropertyValue);
  303. }
  304. void ProtobufObjectPrivate::deserializeUserType(const QMetaProperty &metaType, QByteArray::const_iterator& it, QVariant &newValue)
  305. {
  306. int userType = metaType.userType();
  307. QLatin1Literal typeName(metaType.typeName());
  308. qProtoDebug() << __func__ << "userType" << userType << "currentByte:" << QString::number((*it), 16);
  309. auto serializerIt = serializers.find(userType);
  310. if (serializerIt != std::end(serializers)) {
  311. (serializerIt->second).deserializer(this, it, newValue);
  312. return;
  313. }
  314. if (userType == qMetaTypeId<int32List>()) {
  315. if (typeName == sint32ListTypeNameP
  316. || typeName == sint32ListTypeName) {
  317. newValue = deserializeVarintListTypeZigZag<int32>(it);
  318. } else if (typeName == sfint32ListTypeNameP
  319. || typeName == sfint32ListTypeName) {
  320. newValue = deserializeListType<sfint32>(it);
  321. } else {
  322. newValue = deserializeVarintListType<int32>(it);
  323. }
  324. } else if (userType == qMetaTypeId<int64List>()) {
  325. if (typeName == sint64ListTypeNameP
  326. || typeName == sint64ListTypeName) {
  327. newValue = deserializeVarintListTypeZigZag<int64>(it);
  328. } else if (typeName == sfint64ListTypeNameP
  329. || typeName == sfint64ListTypeName) {
  330. newValue = deserializeListType<sfint64>(it);
  331. } else {
  332. newValue = deserializeVarintListType<int64>(it);
  333. }
  334. } else if (userType == qMetaTypeId<uint32List>()) {
  335. if (typeName == fint32ListTypeNameP
  336. || typeName == fint32ListTypeName) {
  337. newValue = deserializeListType<fint32>(it);
  338. } else {
  339. newValue = deserializeVarintListType<uint32>(it);
  340. }
  341. } else if (userType == qMetaTypeId<uint64List>()) {
  342. if (typeName == fint64ListTypeNameP
  343. || typeName == fint64ListTypeName) {
  344. newValue = deserializeListType<fint64>(it);
  345. } else {
  346. newValue = deserializeVarintListType<uint64>(it);
  347. }
  348. } else if (userType == qMetaTypeId<FloatList>()) {
  349. newValue = deserializeListType<float>(it);
  350. } else if (userType == qMetaTypeId<DoubleList>()) {
  351. newValue = deserializeListType<double>(it);
  352. }
  353. }