libgig  4.3.0
Serialization.cpp
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2020 Christian Schoenebeck *
4  * <cuse@users.sourceforge.net> *
5  * *
6  * This library is part of libgig. *
7  * *
8  * This library is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this library; if not, write to the Free Software *
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21  * MA 02111-1307 USA *
22  ***************************************************************************/
23 
24 // enable implementation specific declarations in Serialization.h required to
25 // build this C++ unit, which should be ignored in the public API though
26 #define LIBGIG_SERIALIZATION_INTERNAL 1
27 
28 #include "Serialization.h"
29 
30 #include <iostream>
31 #include <string.h> // for memcpy()
32 #include <stdlib.h> // for atof()
33 #ifdef _MSC_VER
34 # include <windows.h>
35 # include <dbghelp.h>
36 #else
37 # include <cxxabi.h>
38 #endif
39 #include "helper.h"
40 
41 #define LIBGIG_EPOCH_TIME ((time_t)0)
42 
43 namespace Serialization {
44 
45  // *************** DataType ***************
46  // *
47 
48  static UID _createNullUID() {
49  const UID uid = { NULL, 0 };
50  return uid;
51  }
52 
53  const UID NO_UID = _createNullUID();
54 
66  bool UID::isValid() const {
67  return id != NULL && id != (void*)-1 && size;
68  }
69 
70  // *************** DataType ***************
71  // *
72 
83  m_size = 0;
84  m_isPointer = false;
85  }
86 
114  DataType::DataType(bool isPointer, int size, String baseType,
115  String customType1, String customType2)
116  {
117  m_size = size;
118  m_isPointer = isPointer;
119  m_baseTypeName = baseType;
120  m_customTypeName = customType1;
121  m_customTypeName2 = customType2;
122  }
123 
134  bool DataType::isValid() const {
135  return m_size;
136  }
137 
143  bool DataType::isPointer() const {
144  return m_isPointer;
145  }
146 
172  bool DataType::isClass() const {
173  return m_baseTypeName == "class";
174  }
175 
196  bool DataType::isPrimitive() const {
197  return !isClass() && !isArray() && !isSet() && !isMap();
198  }
199 
210  bool DataType::isString() const {
211  return m_baseTypeName == "String";
212  }
213 
228  bool DataType::isInteger() const {
229  return m_baseTypeName.substr(0, 3) == "int" ||
230  m_baseTypeName.substr(0, 4) == "uint";
231  }
232 
245  bool DataType::isReal() const {
246  return m_baseTypeName.substr(0, 4) == "real";
247  }
248 
260  bool DataType::isBool() const {
261  return m_baseTypeName == "bool";
262  }
263 
275  bool DataType::isEnum() const {
276  return m_baseTypeName == "enum";
277  }
278 
291  bool DataType::isArray() const {
292  return m_baseTypeName == "Array";
293  }
294 
307  bool DataType::isSet() const {
308  return m_baseTypeName == "Set";
309  }
310 
323  bool DataType::isMap() const {
324  return m_baseTypeName == "Map";
325  }
326 
340  bool DataType::isSigned() const {
341  return m_baseTypeName.substr(0, 3) == "int" ||
342  isReal();
343  }
344 
363  bool DataType::operator==(const DataType& other) const {
364  return m_baseTypeName == other.m_baseTypeName &&
365  m_customTypeName == other.m_customTypeName &&
366  m_customTypeName2 == other.m_customTypeName2 &&
367  (m_size == other.m_size || (isClass() && other.isClass())) &&
368  m_isPointer == other.m_isPointer;
369  }
370 
376  bool DataType::operator!=(const DataType& other) const {
377  return !operator==(other);
378  }
379 
391  bool DataType::operator<(const DataType& other) const {
392  return m_baseTypeName < other.m_baseTypeName ||
393  (m_baseTypeName == other.m_baseTypeName &&
394  (m_customTypeName < other.m_customTypeName ||
395  (m_customTypeName == other.m_customTypeName &&
396  (m_customTypeName2 < other.m_customTypeName2 ||
397  (m_customTypeName2 == other.m_customTypeName2 &&
398  (m_size < other.m_size ||
399  (m_size == other.m_size &&
400  m_isPointer < other.m_isPointer)))))));
401  }
402 
414  bool DataType::operator>(const DataType& other) const {
415  return !(operator==(other) || operator<(other));
416  }
417 
433  String s = m_baseTypeName;
434  if (!m_customTypeName.empty())
435  s += " " + customTypeName(true);
436  if (!m_customTypeName2.empty())
437  s += " " + customTypeName2(true);
438  if (isPointer())
439  s += " pointer";
440  return s;
441  }
442 
473  return m_baseTypeName;
474  }
475 
476  static String _demangleTypeName(const char* name) {
477 #ifdef _MSC_VER
478  const size_t MAXLENGTH = 1024;
479  char result[MAXLENGTH];
480 
481  //FIXME: calling UnDecorateSymbolName() is not thread safe!
482  //Skip the first char
483  size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
484  if (size)
485  {
486  return result;
487  }
488  return name;
489 #else
490  int status;
491  char* result =
492  abi::__cxa_demangle(name, 0, 0, &status);
493  String sResult = result;
494  free(result);
495  return (status == 0) ? sResult : name;
496 #endif
497  }
498 
535  String DataType::customTypeName(bool demangle) const {
536  if (!demangle) return m_customTypeName;
537  return _demangleTypeName(m_customTypeName.c_str());
538  }
539 
547  String DataType::customTypeName2(bool demangle) const {
548  if (!demangle) return m_customTypeName2;
549  return _demangleTypeName(m_customTypeName2.c_str());
550  }
551 
552  // *************** Member ***************
553  // *
554 
568  m_uid = NO_UID;
569  m_offset = 0;
570  }
571 
572  Member::Member(String name, UID uid, ssize_t offset, DataType type) {
573  m_name = name;
574  m_uid = uid;
575  m_offset = offset;
576  m_type = type;
577  }
578 
593  UID Member::uid() const {
594  return m_uid;
595  }
596 
618  return m_name;
619  }
620 
662  ssize_t Member::offset() const {
663  return m_offset;
664  }
665 
670  const DataType& Member::type() const {
671  return m_type;
672  }
673 
684  bool Member::isValid() const {
685  return m_uid && !m_name.empty() && m_type;
686  }
687 
696  bool Member::operator==(const Member& other) const {
697  return m_uid == other.m_uid &&
698  m_offset == other.m_offset &&
699  m_name == other.m_name &&
700  m_type == other.m_type;
701  }
702 
708  bool Member::operator!=(const Member& other) const {
709  return !operator==(other);
710  }
711 
724  bool Member::operator<(const Member& other) const {
725  return m_uid < other.m_uid ||
726  (m_uid == other.m_uid &&
727  (m_offset < other.m_offset ||
728  (m_offset == other.m_offset &&
729  (m_name < other.m_name ||
730  (m_name == other.m_name &&
731  m_type < other.m_type)))));
732  }
733 
746  bool Member::operator>(const Member& other) const {
747  return !(operator==(other) || operator<(other));
748  }
749 
750  // *************** Object ***************
751  // *
752 
765  m_version = 0;
766  m_minVersion = 0;
767  }
768 
786  Object::Object(UIDChain uidChain, DataType type) {
787  m_type = type;
788  m_uid = uidChain;
789  m_version = 0;
790  m_minVersion = 0;
791  //m_data.resize(type.size());
792  }
793 
804  bool Object::isValid() const {
805  return m_type && !m_uid.empty();
806  }
807 
819  UID Object::uid(int index) const {
820  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
821  }
822 
823  static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
824  if (type.isPrimitive() && !type.isPointer()) {
825  if (type.isInteger() || type.isEnum()) {
826  if (type.isSigned()) {
827  if (type.size() == 1)
828  *(int8_t*)ptr = (int8_t) atoll(s);
829  else if (type.size() == 2)
830  *(int16_t*)ptr = (int16_t) atoll(s);
831  else if (type.size() == 4)
832  *(int32_t*)ptr = (int32_t) atoll(s);
833  else if (type.size() == 8)
834  *(int64_t*)ptr = (int64_t) atoll(s);
835  else
836  assert(false /* unknown signed int type size */);
837  } else {
838  if (type.size() == 1)
839  *(uint8_t*)ptr = (uint8_t) atoll(s);
840  else if (type.size() == 2)
841  *(uint16_t*)ptr = (uint16_t) atoll(s);
842  else if (type.size() == 4)
843  *(uint32_t*)ptr = (uint32_t) atoll(s);
844  else if (type.size() == 8)
845  *(uint64_t*)ptr = (uint64_t) atoll(s);
846  else
847  assert(false /* unknown unsigned int type size */);
848  }
849  } else if (type.isReal()) {
850  if (type.size() == sizeof(float))
851  *(float*)ptr = (float) atof(s);
852  else if (type.size() == sizeof(double))
853  *(double*)ptr = (double) atof(s);
854  else
855  assert(false /* unknown floating point type */);
856  } else if (type.isBool()) {
857  String lower = toLowerCase(s);
858  const bool b = lower != "0" && lower != "false" && lower != "no";
859  *(bool*)ptr = b;
860  } else if (type.isString()) {
861  *(String*)ptr = s;
862  } else {
863  assert(false /* no built-in cast from string support for this data type */);
864  }
865  }
866  }
867 
884  const ID& id = uid().id;
885  void* ptr = (void*)id;
886  _setNativeValueFromString(ptr, m_type, s.c_str());
887  }
888 
895  const UIDChain& Object::uidChain() const {
896  return m_uid;
897  }
898 
904  const DataType& Object::type() const {
905  return m_type;
906  }
907 
930  const RawData& Object::rawData() const {
931  return m_data;
932  }
933 
945  return m_version;
946  }
947 
960  return m_minVersion;
961  }
962 
995  std::vector<Member>& Object::members() {
996  return m_members;
997  }
998 
1005  const std::vector<Member>& Object::members() const {
1006  return m_members;
1007  }
1008 
1019  bool Object::operator==(const Object& other) const {
1020  // ignoring all other member variables here
1021  // (since UID stands for "unique" ;-) )
1022  return m_uid == other.m_uid &&
1023  m_type == other.m_type;
1024  }
1025 
1031  bool Object::operator!=(const Object& other) const {
1032  return !operator==(other);
1033  }
1034 
1047  bool Object::operator<(const Object& other) const {
1048  // ignoring all other member variables here
1049  // (since UID stands for "unique" ;-) )
1050  return m_uid < other.m_uid ||
1051  (m_uid == other.m_uid &&
1052  m_type < other.m_type);
1053  }
1054 
1067  bool Object::operator>(const Object& other) const {
1068  return !(operator==(other) || operator<(other));
1069  }
1070 
1089  bool Object::isVersionCompatibleTo(const Object& other) const {
1090  if (this->version() == other.version())
1091  return true;
1092  if (this->version() > other.version())
1093  return this->minVersion() <= other.version();
1094  else
1095  return other.minVersion() <= this->version();
1096  }
1097 
1098  void Object::setVersion(Version v) {
1099  m_version = v;
1100  }
1101 
1102  void Object::setMinVersion(Version v) {
1103  m_minVersion = v;
1104  }
1105 
1136  for (int i = 0; i < m_members.size(); ++i)
1137  if (m_members[i].name() == name)
1138  return m_members[i];
1139  return Member();
1140  }
1141 
1156  Member Object::memberByUID(const UID& uid) const {
1157  if (!uid) return Member();
1158  for (int i = 0; i < m_members.size(); ++i)
1159  if (m_members[i].uid() == uid)
1160  return m_members[i];
1161  return Member();
1162  }
1163 
1164  void Object::remove(const Member& member) {
1165  for (int i = 0; i < m_members.size(); ++i) {
1166  if (m_members[i] == member) {
1167  m_members.erase(m_members.begin() + i);
1168  return;
1169  }
1170  }
1171  }
1172 
1188  std::vector<Member> Object::membersOfType(const DataType& type) const {
1189  std::vector<Member> v;
1190  for (int i = 0; i < m_members.size(); ++i) {
1191  const Member& member = m_members[i];
1192  if (member.type() == type)
1193  v.push_back(member);
1194  }
1195  return v;
1196  }
1197 
1229  int Object::sequenceIndexOf(const Member& member) const {
1230  for (int i = 0; i < m_members.size(); ++i)
1231  if (m_members[i] == member)
1232  return i;
1233  return -1;
1234  }
1235 
1236  // *************** Archive ***************
1237  // *
1238 
1258  m_operation = OPERATION_NONE;
1259  m_root = NO_UID;
1260  m_isModified = false;
1261  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1262  }
1263 
1279  Archive::Archive(const RawData& data) {
1280  m_operation = OPERATION_NONE;
1281  m_root = NO_UID;
1282  m_isModified = false;
1283  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1284  decode(data);
1285  }
1286 
1307  Archive::Archive(const uint8_t* data, size_t size) {
1308  m_operation = OPERATION_NONE;
1309  m_root = NO_UID;
1310  m_isModified = false;
1311  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1312  decode(data, size);
1313  }
1314 
1315  Archive::~Archive() {
1316  }
1317 
1329  return m_allObjects[m_root];
1330  }
1331 
1332  static String _encodeBlob(String data) {
1333  return ToString(data.length()) + ":" + data;
1334  }
1335 
1336  static String _encode(const UID& uid) {
1337  String s;
1338  s += _encodeBlob(ToString(size_t(uid.id)));
1339  s += _encodeBlob(ToString(size_t(uid.size)));
1340  return _encodeBlob(s);
1341  }
1342 
1343  static String _encode(const time_t& time) {
1344  return _encodeBlob(ToString(time));
1345  }
1346 
1347  static String _encode(const DataType& type) {
1348  String s;
1349 
1350  // Srx v1.0 format (mandatory):
1351  s += _encodeBlob(type.baseTypeName());
1352  s += _encodeBlob(type.customTypeName());
1353  s += _encodeBlob(ToString(type.size()));
1354  s += _encodeBlob(ToString(type.isPointer()));
1355 
1356  // Srx v1.1 format:
1357  s += _encodeBlob(type.customTypeName2());
1358 
1359  return _encodeBlob(s);
1360  }
1361 
1362  static String _encode(const UIDChain& chain) {
1363  String s;
1364  for (int i = 0; i < chain.size(); ++i)
1365  s += _encode(chain[i]);
1366  return _encodeBlob(s);
1367  }
1368 
1369  static String _encode(const Member& member) {
1370  String s;
1371  s += _encode(member.uid());
1372  s += _encodeBlob(ToString(member.offset()));
1373  s += _encodeBlob(member.name());
1374  s += _encode(member.type());
1375  return _encodeBlob(s);
1376  }
1377 
1378  static String _encode(const std::vector<Member>& members) {
1379  String s;
1380  for (int i = 0; i < members.size(); ++i)
1381  s += _encode(members[i]);
1382  return _encodeBlob(s);
1383  }
1384 
1385  static String _primitiveObjectValueToString(const Object& obj) {
1386  String s;
1387  const DataType& type = obj.type();
1388  const ID& id = obj.uid().id;
1389  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1390  if (!obj.m_data.empty())
1391  assert(type.size() == obj.m_data.size());
1392  if (type.isPrimitive() && !type.isPointer()) {
1393  if (type.isInteger() || type.isEnum()) {
1394  if (type.isSigned()) {
1395  if (type.size() == 1)
1396  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1397  else if (type.size() == 2)
1398  s = ToString(*(int16_t*)ptr);
1399  else if (type.size() == 4)
1400  s = ToString(*(int32_t*)ptr);
1401  else if (type.size() == 8)
1402  s = ToString(*(int64_t*)ptr);
1403  else
1404  assert(false /* unknown signed int type size */);
1405  } else {
1406  if (type.size() == 1)
1407  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1408  else if (type.size() == 2)
1409  s = ToString(*(uint16_t*)ptr);
1410  else if (type.size() == 4)
1411  s = ToString(*(uint32_t*)ptr);
1412  else if (type.size() == 8)
1413  s = ToString(*(uint64_t*)ptr);
1414  else
1415  assert(false /* unknown unsigned int type size */);
1416  }
1417  } else if (type.isReal()) {
1418  if (type.size() == sizeof(float))
1419  s = ToString(*(float*)ptr);
1420  else if (type.size() == sizeof(double))
1421  s = ToString(*(double*)ptr);
1422  else
1423  assert(false /* unknown floating point type */);
1424  } else if (type.isBool()) {
1425  s = ToString(*(bool*)ptr);
1426  } else if (type.isString()) {
1427  s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1428  } else {
1429  assert(false /* unknown primitive type */);
1430  }
1431  }
1432  return s;
1433  }
1434 
1435  template<typename T>
1436  inline T _stringToNumber(const String& s) {
1437  assert(false /* String cast to unknown primitive number type */);
1438  }
1439 
1440  template<>
1441  inline int64_t _stringToNumber(const String& s) {
1442  return atoll(s.c_str());
1443  }
1444 
1445  template<>
1446  inline double _stringToNumber(const String& s) {
1447  return atof(s.c_str());
1448  }
1449 
1450  template<>
1451  inline bool _stringToNumber(const String& s) {
1452  return (bool) atoll(s.c_str());
1453  }
1454 
1455  template<typename T>
1456  static T _primitiveObjectValueToNumber(const Object& obj) {
1457  T value = 0;
1458  const DataType& type = obj.type();
1459  const ID& id = obj.uid().id;
1460  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1461  if (!obj.m_data.empty())
1462  assert(type.size() == obj.m_data.size());
1463  if (type.isPrimitive() && !type.isPointer()) {
1464  if (type.isInteger() || type.isEnum()) {
1465  if (type.isSigned()) {
1466  if (type.size() == 1)
1467  value = (T)*(int8_t*)ptr;
1468  else if (type.size() == 2)
1469  value = (T)*(int16_t*)ptr;
1470  else if (type.size() == 4)
1471  value = (T)*(int32_t*)ptr;
1472  else if (type.size() == 8)
1473  value = (T)*(int64_t*)ptr;
1474  else
1475  assert(false /* unknown signed int type size */);
1476  } else {
1477  if (type.size() == 1)
1478  value = (T)*(uint8_t*)ptr;
1479  else if (type.size() == 2)
1480  value = (T)*(uint16_t*)ptr;
1481  else if (type.size() == 4)
1482  value = (T)*(uint32_t*)ptr;
1483  else if (type.size() == 8)
1484  value = (T)*(uint64_t*)ptr;
1485  else
1486  assert(false /* unknown unsigned int type size */);
1487  }
1488  } else if (type.isReal()) {
1489  if (type.size() == sizeof(float))
1490  value = (T)*(float*)ptr;
1491  else if (type.size() == sizeof(double))
1492  value = (T)*(double*)ptr;
1493  else
1494  assert(false /* unknown floating point type */);
1495  } else if (type.isBool()) {
1496  value = (T)*(bool*)ptr;
1497  } else if (type.isString()) {
1498  value = _stringToNumber<T>(
1499  obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1500  );
1501  } else {
1502  assert(false /* unknown primitive type */);
1503  }
1504  }
1505  return value;
1506  }
1507 
1508  static String _encodePrimitiveValue(const Object& obj) {
1509  return _encodeBlob( _primitiveObjectValueToString(obj) );
1510  }
1511 
1512  static String _encode(const Object& obj) {
1513  String s;
1514  s += _encode(obj.type());
1515  s += _encodeBlob(ToString(obj.version()));
1516  s += _encodeBlob(ToString(obj.minVersion()));
1517  s += _encode(obj.uidChain());
1518  s += _encode(obj.members());
1519  s += _encodePrimitiveValue(obj);
1520  return _encodeBlob(s);
1521  }
1522 
1523  String _encode(const Archive::ObjectPool& objects) {
1524  String s;
1525  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1526  itObject != objects.end(); ++itObject)
1527  {
1528  const Object& obj = itObject->second;
1529  s += _encode(obj);
1530  }
1531  return _encodeBlob(s);
1532  }
1533 
1534  /*
1535  * Srx format history:
1536  * - 1.0: Initial version.
1537  * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1538  * 2nd custom type name (e.g. "Map" types which always contain two
1539  * user defined types).
1540  */
1541  #define MAGIC_START "Srx1v"
1542  #define ENCODING_FORMAT_MINOR_VERSION 1
1543 
1544  String Archive::_encodeRootBlob() {
1545  String s;
1546  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1547  s += _encode(m_root);
1548  s += _encode(m_allObjects);
1549  s += _encodeBlob(m_name);
1550  s += _encodeBlob(m_comment);
1551  s += _encode(m_timeCreated);
1552  s += _encode(m_timeModified);
1553  return _encodeBlob(s);
1554  }
1555 
1556  void Archive::encode() {
1557  m_rawData.clear();
1558  String s = MAGIC_START;
1559  m_timeModified = time(NULL);
1560  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1561  m_timeCreated = m_timeModified;
1562  s += _encodeRootBlob();
1563  m_rawData.resize(s.length() + 1);
1564  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1565  m_isModified = false;
1566  }
1567 
1568  struct _Blob {
1569  const char* p;
1570  const char* end;
1571  };
1572 
1573  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1574  if (!bThrow && p >= end) {
1575  const _Blob blob = { p, end };
1576  return blob;
1577  }
1578  size_t sz = 0;
1579  for (; true; ++p) {
1580  if (p >= end)
1581  throw Exception("Decode Error: Missing blob");
1582  const char& c = *p;
1583  if (c == ':') break;
1584  if (c < '0' || c > '9')
1585  throw Exception("Decode Error: Missing blob size");
1586  sz *= 10;
1587  sz += size_t(c - '0');
1588  }
1589  ++p;
1590  if (p + sz > end)
1591  throw Exception("Decode Error: Premature end of blob");
1592  const _Blob blob = { p, p + sz };
1593  return blob;
1594  }
1595 
1596  template<typename T_int>
1597  static T_int _popIntBlob(const char*& p, const char* end) {
1598  _Blob blob = _decodeBlob(p, end);
1599  p = blob.p;
1600  end = blob.end;
1601 
1602  T_int sign = 1;
1603  T_int i = 0;
1604  if (p >= end)
1605  throw Exception("Decode Error: premature end of int blob");
1606  if (*p == '-') {
1607  sign = -1;
1608  ++p;
1609  }
1610  for (; p < end; ++p) {
1611  const char& c = *p;
1612  if (c < '0' || c > '9')
1613  throw Exception("Decode Error: Invalid int blob format");
1614  i *= 10;
1615  i += size_t(c - '0');
1616  }
1617  return i * sign;
1618  }
1619 
1620  template<typename T_int>
1621  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1622  const T_int i = _popIntBlob<T_int>(p, end);
1623  *(T_int*)&rawData[0] = i;
1624  }
1625 
1626  template<typename T_real>
1627  static T_real _popRealBlob(const char*& p, const char* end) {
1628  _Blob blob = _decodeBlob(p, end);
1629  p = blob.p;
1630  end = blob.end;
1631 
1632  if (p >= end || (end - p) < 1)
1633  throw Exception("Decode Error: premature end of real blob");
1634 
1635  String s(p, size_t(end - p));
1636 
1637  T_real r;
1638  if (sizeof(T_real) <= sizeof(double))
1639  r = atof(s.c_str());
1640  else
1641  assert(false /* unknown real type */);
1642 
1643  p += s.length();
1644 
1645  return r;
1646  }
1647 
1648  template<typename T_real>
1649  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1650  const T_real r = _popRealBlob<T_real>(p, end);
1651  *(T_real*)&rawData[0] = r;
1652  }
1653 
1654  static String _popStringBlob(const char*& p, const char* end) {
1655  _Blob blob = _decodeBlob(p, end);
1656  p = blob.p;
1657  end = blob.end;
1658  if (end - p < 0)
1659  throw Exception("Decode Error: missing String blob");
1660  String s;
1661  const size_t sz = end - p;
1662  s.resize(sz);
1663  memcpy(&s[0], p, sz);
1664  p += sz;
1665  return s;
1666  }
1667 
1668  static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1669  String s = _popStringBlob(p, end);
1670  rawData.resize(s.length() + 1);
1671  strcpy((char*)&rawData[0], &s[0]);
1672  }
1673 
1674  static time_t _popTimeBlob(const char*& p, const char* end) {
1675  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1676  return (time_t) i;
1677  }
1678 
1679  static DataType _popDataTypeBlob(const char*& p, const char* end) {
1680  _Blob blob = _decodeBlob(p, end);
1681  p = blob.p;
1682  end = blob.end;
1683 
1684  DataType type;
1685 
1686  // Srx v1.0 format (mandatory):
1687  type.m_baseTypeName = _popStringBlob(p, end);
1688  type.m_customTypeName = _popStringBlob(p, end);
1689  type.m_size = _popIntBlob<int>(p, end);
1690  type.m_isPointer = _popIntBlob<bool>(p, end);
1691 
1692  // Srx v1.1 format (optional):
1693  if (p < end)
1694  type.m_customTypeName2 = _popStringBlob(p, end);
1695 
1696  return type;
1697  }
1698 
1699  static UID _popUIDBlob(const char*& p, const char* end) {
1700  _Blob blob = _decodeBlob(p, end);
1701  p = blob.p;
1702  end = blob.end;
1703 
1704  if (p >= end)
1705  throw Exception("Decode Error: premature end of UID blob");
1706 
1707  const ID id = (ID) _popIntBlob<size_t>(p, end);
1708  const size_t size = _popIntBlob<size_t>(p, end);
1709 
1710  const UID uid = { id, size };
1711  return uid;
1712  }
1713 
1714  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1715  _Blob blob = _decodeBlob(p, end);
1716  p = blob.p;
1717  end = blob.end;
1718 
1719  UIDChain chain;
1720  while (p < end) {
1721  const UID uid = _popUIDBlob(p, end);
1722  chain.push_back(uid);
1723  }
1724  assert(!chain.empty());
1725  return chain;
1726  }
1727 
1728  static Member _popMemberBlob(const char*& p, const char* end) {
1729  _Blob blob = _decodeBlob(p, end, false);
1730  p = blob.p;
1731  end = blob.end;
1732 
1733  Member m;
1734  if (p >= end) return m;
1735 
1736  m.m_uid = _popUIDBlob(p, end);
1737  m.m_offset = _popIntBlob<ssize_t>(p, end);
1738  m.m_name = _popStringBlob(p, end);
1739  m.m_type = _popDataTypeBlob(p, end);
1740  assert(m.type());
1741  assert(!m.name().empty());
1742  assert(m.uid().isValid());
1743  return m;
1744  }
1745 
1746  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1747  _Blob blob = _decodeBlob(p, end, false);
1748  p = blob.p;
1749  end = blob.end;
1750 
1751  std::vector<Member> members;
1752  while (p < end) {
1753  const Member member = _popMemberBlob(p, end);
1754  if (member)
1755  members.push_back(member);
1756  else
1757  break;
1758  }
1759  return members;
1760  }
1761 
1762  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1763  const DataType& type = obj.type();
1764  if (type.isPrimitive() && !type.isPointer()) {
1765  obj.m_data.resize(type.size());
1766  if (type.isInteger() || type.isEnum()) {
1767  if (type.isSigned()) {
1768  if (type.size() == 1)
1769  _popIntBlob<int8_t>(p, end, obj.m_data);
1770  else if (type.size() == 2)
1771  _popIntBlob<int16_t>(p, end, obj.m_data);
1772  else if (type.size() == 4)
1773  _popIntBlob<int32_t>(p, end, obj.m_data);
1774  else if (type.size() == 8)
1775  _popIntBlob<int64_t>(p, end, obj.m_data);
1776  else
1777  assert(false /* unknown signed int type size */);
1778  } else {
1779  if (type.size() == 1)
1780  _popIntBlob<uint8_t>(p, end, obj.m_data);
1781  else if (type.size() == 2)
1782  _popIntBlob<uint16_t>(p, end, obj.m_data);
1783  else if (type.size() == 4)
1784  _popIntBlob<uint32_t>(p, end, obj.m_data);
1785  else if (type.size() == 8)
1786  _popIntBlob<uint64_t>(p, end, obj.m_data);
1787  else
1788  assert(false /* unknown unsigned int type size */);
1789  }
1790  } else if (type.isReal()) {
1791  if (type.size() == sizeof(float))
1792  _popRealBlob<float>(p, end, obj.m_data);
1793  else if (type.size() == sizeof(double))
1794  _popRealBlob<double>(p, end, obj.m_data);
1795  else
1796  assert(false /* unknown floating point type */);
1797  } else if (type.isBool()) {
1798  _popIntBlob<uint8_t>(p, end, obj.m_data);
1799  } else if (type.isString()) {
1800  _popStringBlob(p, end, obj.m_data);
1801  } else {
1802  assert(false /* unknown primitive type */);
1803  }
1804 
1805  } else {
1806  // don't whine if the empty blob was not added on encoder side
1807  _Blob blob = _decodeBlob(p, end, false);
1808  p = blob.p;
1809  end = blob.end;
1810  }
1811  }
1812 
1813  static Object _popObjectBlob(const char*& p, const char* end) {
1814  _Blob blob = _decodeBlob(p, end, false);
1815  p = blob.p;
1816  end = blob.end;
1817 
1818  Object obj;
1819  if (p >= end) return obj;
1820 
1821  obj.m_type = _popDataTypeBlob(p, end);
1822  obj.m_version = _popIntBlob<Version>(p, end);
1823  obj.m_minVersion = _popIntBlob<Version>(p, end);
1824  obj.m_uid = _popUIDChainBlob(p, end);
1825  obj.m_members = _popMembersBlob(p, end);
1826  _popPrimitiveValue(p, end, obj);
1827  assert(obj.type());
1828  return obj;
1829  }
1830 
1831  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1832  _Blob blob = _decodeBlob(p, end, false);
1833  p = blob.p;
1834  end = blob.end;
1835 
1836  if (p >= end)
1837  throw Exception("Decode Error: Premature end of objects blob");
1838 
1839  while (true) {
1840  const Object obj = _popObjectBlob(p, end);
1841  if (!obj) break;
1842  m_allObjects[obj.uid()] = obj;
1843  }
1844  }
1845 
1846  void Archive::_popRootBlob(const char*& p, const char* end) {
1847  _Blob blob = _decodeBlob(p, end, false);
1848  p = blob.p;
1849  end = blob.end;
1850 
1851  if (p >= end)
1852  throw Exception("Decode Error: Premature end of root blob");
1853 
1854  // just in case this encoding format will be extended in future
1855  // (currently not used)
1856  const int formatMinorVersion = _popIntBlob<int>(p, end);
1857 
1858  m_root = _popUIDBlob(p, end);
1859  if (!m_root)
1860  throw Exception("Decode Error: No root object");
1861 
1862  _popObjectsBlob(p, end);
1863  if (!m_allObjects[m_root])
1864  throw Exception("Decode Error: Missing declared root object");
1865 
1866  m_name = _popStringBlob(p, end);
1867  m_comment = _popStringBlob(p, end);
1868  m_timeCreated = _popTimeBlob(p, end);
1869  m_timeModified = _popTimeBlob(p, end);
1870  }
1871 
1887  void Archive::decode(const RawData& data) {
1888  m_rawData = data;
1889  m_allObjects.clear();
1890  m_isModified = false;
1891  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1892  const char* p = (const char*) &data[0];
1893  const char* end = p + data.size();
1894  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1895  throw Exception("Decode Error: Magic start missing!");
1896  p += strlen(MAGIC_START);
1897  _popRootBlob(p, end);
1898  }
1899 
1920  void Archive::decode(const uint8_t* data, size_t size) {
1921  RawData rawData;
1922  rawData.resize(size);
1923  memcpy(&rawData[0], data, size);
1924  decode(rawData);
1925  }
1926 
1943  if (m_isModified) encode();
1944  return m_rawData;
1945  }
1946 
1953  return MAGIC_START;
1954  }
1955 
1970  bool Archive::isModified() const {
1971  return m_isModified;
1972  }
1973 
1980  m_allObjects.clear();
1981  m_operation = OPERATION_NONE;
1982  m_root = NO_UID;
1983  m_rawData.clear();
1984  m_isModified = false;
1985  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1986  }
1987 
1996  return m_name;
1997  }
1998 
2009  if (m_name == name) return;
2010  m_name = name;
2011  m_isModified = true;
2012  }
2013 
2022  return m_comment;
2023  }
2024 
2034  void Archive::setComment(String comment) {
2035  if (m_comment == comment) return;
2036  m_comment = comment;
2037  m_isModified = true;
2038  }
2039 
2040  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2041  tm* pTm;
2042  switch (base) {
2043  case LOCAL_TIME:
2044  pTm = localtime(&time);
2045  break;
2046  case UTC_TIME:
2047  pTm = gmtime(&time);
2048  break;
2049  default:
2050  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2051  }
2052  if (!pTm)
2053  throw Exception("Failed assembling time stamp structure");
2054  return *pTm;
2055  }
2056 
2062  time_t Archive::timeStampCreated() const {
2063  return m_timeCreated;
2064  }
2065 
2072  return m_timeModified;
2073  }
2074 
2086  return _convertTimeStamp(m_timeCreated, base);
2087  }
2088 
2100  return _convertTimeStamp(m_timeModified, base);
2101  }
2102 
2120  void Archive::removeMember(Object& parent, const Member& member) {
2121  parent.remove(member);
2122  m_isModified = true;
2123  }
2124 
2140  void Archive::remove(const Object& obj) {
2141  //FIXME: Should traverse from root object and remove all members associated with this object
2142  if (!obj.uid()) return;
2143  m_allObjects.erase(obj.uid());
2144  m_isModified = true;
2145  }
2146 
2159  return m_allObjects[uid];
2160  }
2161 
2173  if (!object) return;
2174  object.setVersion(v);
2175  m_isModified = true;
2176  }
2177 
2189  if (!object) return;
2190  object.setMinVersion(v);
2191  m_isModified = true;
2192  }
2193 
2202  void Archive::setEnumValue(Object& object, uint64_t value) {
2203  if (!object) return;
2204  if (!object.type().isEnum())
2205  throw Exception("Not an enum data type");
2206  Object* pObject = &object;
2207  if (object.type().isPointer()) {
2208  Object& obj = objectByUID(object.uid(1));
2209  if (!obj) return;
2210  pObject = &obj;
2211  }
2212  const int nativeEnumSize = sizeof(enum operation_t);
2213  DataType& type = const_cast<DataType&>( pObject->type() );
2214  // original serializer ("sender") might have had a different word size
2215  // than this machine, adjust type object in this case
2216  if (type.size() != nativeEnumSize) {
2217  type.m_size = nativeEnumSize;
2218  }
2219  pObject->m_data.resize(type.size());
2220  void* ptr = &pObject->m_data[0];
2221  if (type.size() == 1)
2222  *(uint8_t*)ptr = (uint8_t)value;
2223  else if (type.size() == 2)
2224  *(uint16_t*)ptr = (uint16_t)value;
2225  else if (type.size() == 4)
2226  *(uint32_t*)ptr = (uint32_t)value;
2227  else if (type.size() == 8)
2228  *(uint64_t*)ptr = (uint64_t)value;
2229  else
2230  assert(false /* unknown enum type size */);
2231  m_isModified = true;
2232  }
2233 
2244  void Archive::setIntValue(Object& object, int64_t value) {
2245  if (!object) return;
2246  if (!object.type().isInteger())
2247  throw Exception("Not an integer data type");
2248  Object* pObject = &object;
2249  if (object.type().isPointer()) {
2250  Object& obj = objectByUID(object.uid(1));
2251  if (!obj) return;
2252  pObject = &obj;
2253  }
2254  const DataType& type = pObject->type();
2255  pObject->m_data.resize(type.size());
2256  void* ptr = &pObject->m_data[0];
2257  if (type.isSigned()) {
2258  if (type.size() == 1)
2259  *(int8_t*)ptr = (int8_t)value;
2260  else if (type.size() == 2)
2261  *(int16_t*)ptr = (int16_t)value;
2262  else if (type.size() == 4)
2263  *(int32_t*)ptr = (int32_t)value;
2264  else if (type.size() == 8)
2265  *(int64_t*)ptr = (int64_t)value;
2266  else
2267  assert(false /* unknown signed int type size */);
2268  } else {
2269  if (type.size() == 1)
2270  *(uint8_t*)ptr = (uint8_t)value;
2271  else if (type.size() == 2)
2272  *(uint16_t*)ptr = (uint16_t)value;
2273  else if (type.size() == 4)
2274  *(uint32_t*)ptr = (uint32_t)value;
2275  else if (type.size() == 8)
2276  *(uint64_t*)ptr = (uint64_t)value;
2277  else
2278  assert(false /* unknown unsigned int type size */);
2279  }
2280  m_isModified = true;
2281  }
2282 
2294  void Archive::setRealValue(Object& object, double value) {
2295  if (!object) return;
2296  if (!object.type().isReal())
2297  throw Exception("Not a real data type");
2298  Object* pObject = &object;
2299  if (object.type().isPointer()) {
2300  Object& obj = objectByUID(object.uid(1));
2301  if (!obj) return;
2302  pObject = &obj;
2303  }
2304  const DataType& type = pObject->type();
2305  pObject->m_data.resize(type.size());
2306  void* ptr = &pObject->m_data[0];
2307  if (type.size() == sizeof(float))
2308  *(float*)ptr = (float)value;
2309  else if (type.size() == sizeof(double))
2310  *(double*)ptr = (double)value;
2311  else
2312  assert(false /* unknown real type size */);
2313  m_isModified = true;
2314  }
2315 
2324  void Archive::setBoolValue(Object& object, bool value) {
2325  if (!object) return;
2326  if (!object.type().isBool())
2327  throw Exception("Not a bool data type");
2328  Object* pObject = &object;
2329  if (object.type().isPointer()) {
2330  Object& obj = objectByUID(object.uid(1));
2331  if (!obj) return;
2332  pObject = &obj;
2333  }
2334  const DataType& type = pObject->type();
2335  pObject->m_data.resize(type.size());
2336  bool* ptr = (bool*)&pObject->m_data[0];
2337  *ptr = value;
2338  m_isModified = true;
2339  }
2340 
2349  void Archive::setStringValue(Object& object, String value) {
2350  if (!object) return;
2351  if (!object.type().isString())
2352  throw Exception("Not a String data type");
2353  Object* pObject = &object;
2354  if (object.type().isPointer()) {
2355  Object& obj = objectByUID(object.uid(1));
2356  if (!obj) return;
2357  pObject = &obj;
2358  }
2359  pObject->m_data.resize(value.length() + 1);
2360  char* ptr = (char*) &pObject->m_data[0];
2361  strcpy(ptr, &value[0]);
2362  m_isModified = true;
2363  }
2364 
2378  void Archive::setAutoValue(Object& object, String value) {
2379  if (!object) return;
2380  const DataType& type = object.type();
2381  if (type.isInteger())
2382  setIntValue(object, atoll(value.c_str()));
2383  else if (type.isReal())
2384  setRealValue(object, atof(value.c_str()));
2385  else if (type.isBool()) {
2386  String val = toLowerCase(value);
2387  if (val == "true" || val == "yes" || val == "1")
2388  setBoolValue(object, true);
2389  else if (val == "false" || val == "no" || val == "0")
2390  setBoolValue(object, false);
2391  else
2392  setBoolValue(object, atof(value.c_str()));
2393  } else if (type.isString())
2394  setStringValue(object, value);
2395  else if (type.isEnum())
2396  setEnumValue(object, atoll(value.c_str()));
2397  else
2398  throw Exception("Not a primitive data type");
2399  }
2400 
2411  if (!object)
2412  throw Exception("Invalid object");
2413  if (object.type().isClass())
2414  throw Exception("Object is class type");
2415  const Object* pObject = &object;
2416  if (object.type().isPointer()) {
2417  const Object& obj = objectByUID(object.uid(1));
2418  if (!obj) return "";
2419  pObject = &obj;
2420  }
2421  return _primitiveObjectValueToString(*pObject);
2422  }
2423 
2433  int64_t Archive::valueAsInt(const Object& object) {
2434  if (!object)
2435  throw Exception("Invalid object");
2436  if (!object.type().isInteger() && !object.type().isEnum())
2437  throw Exception("Object is neither an integer nor an enum");
2438  const Object* pObject = &object;
2439  if (object.type().isPointer()) {
2440  const Object& obj = objectByUID(object.uid(1));
2441  if (!obj) return 0;
2442  pObject = &obj;
2443  }
2444  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2445  }
2446 
2456  double Archive::valueAsReal(const Object& object) {
2457  if (!object)
2458  throw Exception("Invalid object");
2459  if (!object.type().isReal())
2460  throw Exception("Object is not an real type");
2461  const Object* pObject = &object;
2462  if (object.type().isPointer()) {
2463  const Object& obj = objectByUID(object.uid(1));
2464  if (!obj) return 0;
2465  pObject = &obj;
2466  }
2467  return _primitiveObjectValueToNumber<double>(*pObject);
2468  }
2469 
2478  bool Archive::valueAsBool(const Object& object) {
2479  if (!object)
2480  throw Exception("Invalid object");
2481  if (!object.type().isBool())
2482  throw Exception("Object is not a bool");
2483  const Object* pObject = &object;
2484  if (object.type().isPointer()) {
2485  const Object& obj = objectByUID(object.uid(1));
2486  if (!obj) return 0;
2487  pObject = &obj;
2488  }
2489  return _primitiveObjectValueToNumber<bool>(*pObject);
2490  }
2491 
2492  Archive::operation_t Archive::operation() const {
2493  return m_operation;
2494  }
2495 
2496  // *************** Archive::Syncer ***************
2497  // *
2498 
2499  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2500  : m_dst(dst), m_src(src)
2501  {
2502  const Object srcRootObj = src.rootObject();
2503  const Object dstRootObj = dst.rootObject();
2504  if (!srcRootObj)
2505  throw Exception("No source root object!");
2506  if (!dstRootObj)
2507  throw Exception("Expected destination root object not found!");
2508  syncObject(dstRootObj, srcRootObj);
2509  }
2510 
2511  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2512  assert(srcObj.rawData().size() == dstObj.type().size());
2513  void* pDst = (void*)dstObj.uid().id;
2514  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2515  }
2516 
2517  void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2518  assert(dstObj.type().isString());
2519  assert(dstObj.type() == srcObj.type());
2520  String* pDst = (String*)(void*)dstObj.uid().id;
2521  *pDst = (String) (const char*) &srcObj.rawData()[0];
2522  }
2523 
2524  void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2525  assert(dstObj.type().isArray());
2526  assert(dstObj.type() == srcObj.type());
2527  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2528  }
2529 
2530  void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2531  assert(dstObj.type().isSet());
2532  assert(dstObj.type() == srcObj.type());
2533  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2534  }
2535 
2536  void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2537  assert(dstObj.type().isMap());
2538  assert(dstObj.type() == srcObj.type());
2539  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2540  }
2541 
2542  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2543  assert(dstObj.type().isPointer());
2544  assert(dstObj.type() == srcObj.type());
2545  const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2546  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2547  syncObject(pointedDstObject, pointedSrcObject);
2548  }
2549 
2550  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2551  if (!dstObj || !srcObj) return; // end of recursion
2552  if (!dstObj.isVersionCompatibleTo(srcObj))
2553  throw Exception("Version incompatible (destination version " +
2554  ToString(dstObj.version()) + " [min. version " +
2555  ToString(dstObj.minVersion()) + "], source version " +
2556  ToString(srcObj.version()) + " [min. version " +
2557  ToString(srcObj.minVersion()) + "])");
2558  if (dstObj.type() != srcObj.type())
2559  throw Exception("Incompatible data structure type (destination type " +
2560  dstObj.type().asLongDescr() + " vs. source type " +
2561  srcObj.type().asLongDescr() + ")");
2562 
2563  // prevent syncing this object again, and thus also prevent endless
2564  // loop on data structures with cyclic relations
2565  m_dst.m_allObjects.erase(dstObj.uid());
2566 
2567  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2568  if (dstObj.type().isString())
2569  syncString(dstObj, srcObj);
2570  else
2571  syncPrimitive(dstObj, srcObj);
2572  return; // end of recursion
2573  }
2574 
2575  if (dstObj.type().isArray()) {
2576  syncArray(dstObj, srcObj);
2577  return;
2578  }
2579 
2580  if (dstObj.type().isSet()) {
2581  syncSet(dstObj, srcObj);
2582  return;
2583  }
2584 
2585  if (dstObj.type().isMap()) {
2586  syncMap(dstObj, srcObj);
2587  return;
2588  }
2589 
2590  if (dstObj.type().isPointer()) {
2591  syncPointer(dstObj, srcObj);
2592  return;
2593  }
2594 
2595  assert(dstObj.type().isClass());
2596  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2597  const Member& srcMember = srcObj.members()[iMember];
2598  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2599  if (!dstMember)
2600  throw Exception("Expected member missing in destination object");
2601  syncMember(dstMember, srcMember);
2602  }
2603  }
2604 
2605  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2606  Member dstMember = dstObj.memberNamed(srcMember.name());
2607  if (dstMember)
2608  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2609  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2610  if (members.size() <= 0)
2611  return Member();
2612  if (members.size() == 1)
2613  return members[0];
2614  for (int i = 0; i < members.size(); ++i)
2615  if (members[i].offset() == srcMember.offset())
2616  return members[i];
2617  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2618  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2619  for (int i = 0; i < members.size(); ++i) {
2620  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2621  if (dstSeqNr == srcSeqNr)
2622  return members[i];
2623  }
2624  return Member(); // give up!
2625  }
2626 
2627  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2628  assert(dstMember && srcMember);
2629  assert(dstMember.type() == srcMember.type());
2630  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2631  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2632  syncObject(dstObj, srcObj);
2633  }
2634 
2635  // *************** Exception ***************
2636  // *
2637 
2638  Exception::Exception() {
2639  }
2640 
2641  Exception::Exception(String format, ...) {
2642  va_list arg;
2643  va_start(arg, format);
2644  Message = assemble(format, arg);
2645  va_end(arg);
2646  }
2647 
2648  Exception::Exception(String format, va_list arg) {
2649  Message = assemble(format, arg);
2650  }
2651 
2658  std::cout << "Serialization::Exception: " << Message << std::endl;
2659  }
2660 
2661  String Exception::assemble(String format, va_list arg) {
2662  char* buf = NULL;
2663  vasprintf(&buf, format.c_str(), arg);
2664  String s = buf;
2665  free(buf);
2666  return s;
2667  }
2668 
2669 } // namespace Serialization
Serialization::DataType::operator<
bool operator<(const DataType &other) const
Smaller than comparison.
Definition: Serialization.cpp:391
Serialization::Archive::setIntValue
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
Definition: Serialization.cpp:2244
Serialization::Object::memberByUID
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
Definition: Serialization.cpp:1156
Serialization::Object::rawData
const RawData & rawData() const
Raw data of the original native C/C++ data.
Definition: Serialization.cpp:930
Serialization::Version
uint32_t Version
Version number data type.
Definition: Serialization.h:209
Serialization::Archive::objectByUID
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
Definition: Serialization.cpp:2158
Serialization::Object::uidChain
const UIDChain & uidChain() const
Unique identifier chain of this Object.
Definition: Serialization.cpp:895
Serialization::Member::operator==
bool operator==(const Member &other) const
Comparison for equalness.
Definition: Serialization.cpp:696
Serialization::DataType::isPointer
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
Definition: Serialization.cpp:143
Serialization::Member
Abstract reflection of a native C++ class/struct's member variable.
Definition: Serialization.h:650
Serialization::DataType::operator>
bool operator>(const DataType &other) const
Greater than comparison.
Definition: Serialization.cpp:414
Serialization::DataType::isEnum
bool isEnum() const
Whether this is a C/C++ enum data type.
Definition: Serialization.cpp:275
Serialization::Archive::valueAsBool
bool valueAsBool(const Object &object)
Get boolean value of object.
Definition: Serialization.cpp:2478
Serialization::Archive::Archive
Archive()
Create an "empty" archive.
Definition: Serialization.cpp:1257
Serialization::UIDChain
std::vector< UID > UIDChain
Chain of UIDs.
Definition: Serialization.h:402
Serialization::DataType::isSet
bool isSet() const
Whether this is a C++ Set<> object type.
Definition: Serialization.cpp:307
Serialization::Archive::clear
void clear()
Clear content of this archive.
Definition: Serialization.cpp:1979
Serialization::Archive::operation_t
operation_t
Current activity of Archive object.
Definition: Serialization.h:899
Serialization::Archive::name
String name() const
Optional name of this archive.
Definition: Serialization.cpp:1995
Serialization::Archive::valueAsInt
int64_t valueAsInt(const Object &object)
Get integer value of object.
Definition: Serialization.cpp:2433
Serialization::DataType::isString
bool isString() const
Whether this is a C++ String data type.
Definition: Serialization.cpp:210
Serialization::DataType::isBool
bool isBool() const
Whether this is a boolean C/C++ data type.
Definition: Serialization.cpp:260
Serialization::Archive::setBoolValue
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
Definition: Serialization.cpp:2324
Serialization::Archive::comment
String comment() const
Optional comments for this archive.
Definition: Serialization.cpp:2021
Serialization::Archive::rawDataFormat
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
Definition: Serialization.cpp:1952
Serialization::DataType::isMap
bool isMap() const
Whether this is a C++ Map<> object type.
Definition: Serialization.cpp:323
Serialization::Archive::setRealValue
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
Definition: Serialization.cpp:2294
Serialization::Object::setNativeValueFromString
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
Definition: Serialization.cpp:883
Serialization::Archive::dateTimeCreated
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Definition: Serialization.cpp:2085
Serialization::Object::isValid
bool isValid() const
Check if this is a valid Object instance.
Definition: Serialization.cpp:804
Serialization::Object::isVersionCompatibleTo
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Definition: Serialization.cpp:1089
Serialization::Archive::isModified
bool isModified() const
Whether this archive was modified.
Definition: Serialization.cpp:1970
Serialization::RawData
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
Definition: Serialization.h:188
Serialization::DataType::isArray
bool isArray() const
Whether this is a C++ Array<> object type.
Definition: Serialization.cpp:291
Serialization::LOCAL_TIME
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...
Definition: Serialization.h:217
Serialization::Object::operator==
bool operator==(const Object &other) const
Comparison for equalness.
Definition: Serialization.cpp:1019
Serialization::Exception
Will be thrown whenever an error occurs during an serialization or deserialization process.
Definition: Serialization.h:1668
Serialization::ID
void * ID
Abstract identifier for serialized C++ objects.
Definition: Serialization.h:200
Serialization::DataType::isInteger
bool isInteger() const
Whether this is an integer C/C++ data type.
Definition: Serialization.cpp:228
Serialization::DataType::asLongDescr
String asLongDescr() const
Human readable long description for this data type.
Definition: Serialization.cpp:432
Serialization::Archive::setName
void setName(String name)
Assign a name to this archive.
Definition: Serialization.cpp:2008
Serialization::DataType::isSigned
bool isSigned() const
Whether this is a signed integer C/C++ data type.
Definition: Serialization.cpp:340
Serialization::DataType::DataType
DataType()
Default constructor (as "invalid" DataType).
Definition: Serialization.cpp:82
Serialization::Object::members
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
Definition: Serialization.cpp:995
Serialization::Object
Abstract reflection of some native serialized C/C++ data.
Definition: Serialization.h:704
Serialization::Archive::rawData
const RawData & rawData()
Raw data stream of this archive content.
Definition: Serialization.cpp:1942
Serialization::String
std::string String
Textual string.
Definition: Serialization.h:121
Serialization::Archive::OPERATION_NONE
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
Definition: Serialization.h:900
Serialization::UID
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
Definition: Serialization.h:319
Serialization::Archive::setAutoValue
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
Definition: Serialization.cpp:2378
Serialization::Object::version
Version version() const
Version of original user defined C/C++ struct or class.
Definition: Serialization.cpp:944
Serialization::Object::operator<
bool operator<(const Object &other) const
Smaller than comparison.
Definition: Serialization.cpp:1047
Serialization::Object::type
const DataType & type() const
C/C++ data type this Object is reflecting.
Definition: Serialization.cpp:904
Serialization::time_base_t
time_base_t
To which time zone a certain timing information relates to.
Definition: Serialization.h:216
Serialization::Archive::setVersion
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
Definition: Serialization.h:1245
Serialization::UID::size
size_t size
Memory size of the object or member in question.
Definition: Serialization.h:322
Serialization::DataType::operator!=
bool operator!=(const DataType &other) const
Comparison for inequalness.
Definition: Serialization.cpp:376
Serialization::Object::sequenceIndexOf
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
Definition: Serialization.cpp:1229
Serialization::Exception::PrintMessage
void PrintMessage()
Print exception message to stdout.
Definition: Serialization.cpp:2657
Serialization::Member::type
const DataType & type() const
C/C++ Data type of this member.
Definition: Serialization.cpp:670
Serialization::Object::Object
Object()
Default constructor (for an "invalid" Object).
Definition: Serialization.cpp:764
Serialization::DataType::isPrimitive
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
Definition: Serialization.cpp:196
Serialization::Archive::timeStampModified
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
Definition: Serialization.cpp:2071
Serialization::Object::minVersion
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
Definition: Serialization.cpp:959
Serialization::Object::operator!=
bool operator!=(const Object &other) const
Comparison for inequalness.
Definition: Serialization.cpp:1031
Serialization::Member::offset
ssize_t offset() const
Offset of member in its containing parent data structure.
Definition: Serialization.cpp:662
Serialization::DataType::operator==
bool operator==(const DataType &other) const
Comparison for equalness.
Definition: Serialization.cpp:363
Serialization::Archive::timeStampCreated
time_t timeStampCreated() const
Date and time when this archive was initially created.
Definition: Serialization.cpp:2062
Serialization::Archive::rootObject
Object & rootObject()
Root C++ object of this archive.
Definition: Serialization.cpp:1328
Serialization::Archive::valueAsString
String valueAsString(const Object &object)
Get value of object as string.
Definition: Serialization.cpp:2410
Serialization::Archive::valueAsReal
double valueAsReal(const Object &object)
Get floating point value of object.
Definition: Serialization.cpp:2456
Serialization::DataType::isClass
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
Definition: Serialization.cpp:172
Serialization::Object::memberNamed
Member memberNamed(String name) const
Get the member of this Object with given name.
Definition: Serialization.cpp:1135
Serialization::Archive::decode
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
Definition: Serialization.cpp:1887
Serialization::Member::uid
UID uid() const
Unique identifier of this member instance.
Definition: Serialization.cpp:593
Serialization::Archive::setMinVersion
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
Definition: Serialization.h:1286
Serialization::UTC_TIME
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
Definition: Serialization.h:218
Serialization::Object::uid
UID uid(int index=0) const
Unique identifier of this Object.
Definition: Serialization.cpp:819
Serialization::DataType::isReal
bool isReal() const
Whether this is a floating point based C/C++ data type.
Definition: Serialization.cpp:245
Serialization::DataType::isValid
bool isValid() const
Check if this is a valid DataType object.
Definition: Serialization.cpp:134
Serialization::DataType
Abstract reflection of a native C++ data type.
Definition: Serialization.h:433
Serialization::DataType::size
size_t size() const
Returns native memory size of the respective C++ object or variable.
Definition: Serialization.h:436
Serialization::Archive::removeMember
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
Definition: Serialization.cpp:2120
Serialization
Serialization / deserialization framework.
Definition: gig.h:98
Serialization::Archive::setComment
void setComment(String comment)
Assign a comment to this archive.
Definition: Serialization.cpp:2034
Serialization::Archive::setEnumValue
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
Definition: Serialization.cpp:2202
Serialization::Archive::remove
void remove(const Object &obj)
Remove an object from this archive.
Definition: Serialization.cpp:2140
Serialization::Member::isValid
bool isValid() const
Check if this is a valid Member object.
Definition: Serialization.cpp:684
Serialization::NO_UID
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
Definition: Serialization.cpp:53
Serialization::Archive::dateTimeModified
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Definition: Serialization.cpp:2099
Serialization::DataType::customTypeName
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
Definition: Serialization.cpp:535
Serialization::DataType::customTypeName2
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
Definition: Serialization.cpp:547
Serialization::Object::operator>
bool operator>(const Object &other) const
Greater than comparison.
Definition: Serialization.cpp:1067
Serialization::UID::id
ID id
Abstract non-unique ID of the object or member in question.
Definition: Serialization.h:321
Serialization::Member::operator<
bool operator<(const Member &other) const
Smaller than comparison.
Definition: Serialization.cpp:724
Serialization::Member::operator!=
bool operator!=(const Member &other) const
Comparison for inequalness.
Definition: Serialization.cpp:708
Serialization::Archive::setStringValue
void setStringValue(Object &object, String value)
Set new textual string for given String object.
Definition: Serialization.cpp:2349
Serialization::UID::isValid
bool isValid() const
Check whether this is a valid unique identifier.
Definition: Serialization.cpp:66
Serialization::DataType::baseTypeName
String baseTypeName() const
The base type name of this data type.
Definition: Serialization.cpp:472
Serialization::Member::Member
Member()
Default constructor.
Definition: Serialization.cpp:567
Serialization::Member::name
String name() const
Name of the member.
Definition: Serialization.cpp:617
Serialization::Member::operator>
bool operator>(const Member &other) const
Greater than comparison.
Definition: Serialization.cpp:746
Serialization::Object::membersOfType
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
Definition: Serialization.cpp:1188