libgig  4.5.0.svn7
Serialization.cpp
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2025 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 #include <cstdint> // for uintptr_t
34 #ifdef _MSC_VER
35 # include <windows.h>
36 # include <dbghelp.h>
37 #else
38 # include <cxxabi.h>
39 #endif
40 #include "helper.h"
41 
42 #define LIBGIG_EPOCH_TIME ((time_t)0)
43 
44 namespace Serialization {
45 
46  // *************** DataType ***************
47  // *
48 
49  static UID _createNullUID() {
50  const UID uid = { NULL, 0 };
51  return uid;
52  }
53 
54  const UID NO_UID = _createNullUID();
55 
67  bool UID::isValid() const {
68  return id != NULL && id != (void*)-1 && size;
69  }
70 
71  // *************** DataType ***************
72  // *
73 
85  std::map<String,std::function<Object(Archive*)>> DataType::m_allocFns;
86 
97  m_size = 0;
98  m_isPointer = false;
99  }
100 
128  DataType::DataType(bool isPointer, int size, String baseType,
129  String customType1, String customType2)
130  {
131  m_size = size;
132  m_isPointer = isPointer;
133  m_baseTypeName = baseType;
134  m_customTypeName = customType1;
135  m_customTypeName2 = customType2;
136  }
137 
148  bool DataType::isValid() const {
149  return m_size;
150  }
151 
157  bool DataType::isPointer() const {
158  return m_isPointer;
159  }
160 
186  bool DataType::isClass() const {
187  return m_baseTypeName == "class";
188  }
189 
210  bool DataType::isPrimitive() const {
211  return !isClass() && !isArray() && !isSet() && !isMap();
212  }
213 
224  bool DataType::isString() const {
225  return m_baseTypeName == "String";
226  }
227 
242  bool DataType::isInteger() const {
243  return m_baseTypeName.substr(0, 3) == "int" ||
244  m_baseTypeName.substr(0, 4) == "uint";
245  }
246 
259  bool DataType::isReal() const {
260  return m_baseTypeName.substr(0, 4) == "real";
261  }
262 
274  bool DataType::isBool() const {
275  return m_baseTypeName == "bool";
276  }
277 
289  bool DataType::isEnum() const {
290  return m_baseTypeName == "enum";
291  }
292 
305  bool DataType::isArray() const {
306  return m_baseTypeName == "Array";
307  }
308 
321  bool DataType::isSet() const {
322  return m_baseTypeName == "Set";
323  }
324 
337  bool DataType::isMap() const {
338  return m_baseTypeName == "Map";
339  }
340 
354  bool DataType::isSigned() const {
355  return m_baseTypeName.substr(0, 3) == "int" ||
356  isReal();
357  }
358 
377  bool DataType::operator==(const DataType& other) const {
378  return m_baseTypeName == other.m_baseTypeName &&
379  m_customTypeName == other.m_customTypeName &&
380  m_customTypeName2 == other.m_customTypeName2 &&
381  (m_size == other.m_size || (isClass() && other.isClass())) &&
382  m_isPointer == other.m_isPointer;
383  }
384 
398  return m_baseTypeName + "," +
399  m_customTypeName + "," +
400  m_customTypeName2 + "," +
401  ToString(m_size) + "," +
402  ToString(isClass()) + "," +
403  ToString(m_isPointer);
404  }
405 
411  bool DataType::operator!=(const DataType& other) const {
412  return !operator==(other);
413  }
414 
426  bool DataType::operator<(const DataType& other) const {
427  return m_baseTypeName < other.m_baseTypeName ||
428  (m_baseTypeName == other.m_baseTypeName &&
429  (m_customTypeName < other.m_customTypeName ||
430  (m_customTypeName == other.m_customTypeName &&
431  (m_customTypeName2 < other.m_customTypeName2 ||
432  (m_customTypeName2 == other.m_customTypeName2 &&
433  (m_size < other.m_size ||
434  (m_size == other.m_size &&
435  m_isPointer < other.m_isPointer)))))));
436  }
437 
449  bool DataType::operator>(const DataType& other) const {
450  return !(operator==(other) || operator<(other));
451  }
452 
468  String s = m_baseTypeName;
469  if (!m_customTypeName.empty())
470  s += " " + customTypeName(true);
471  if (!m_customTypeName2.empty())
472  s += " " + customTypeName2(true);
473  if (isPointer())
474  s += " pointer";
475  return s;
476  }
477 
508  return m_baseTypeName;
509  }
510 
511  static String _demangleTypeName(const char* name) {
512 #ifdef _MSC_VER
513  const size_t MAXLENGTH = 1024;
514  char result[MAXLENGTH];
515 
516  //FIXME: calling UnDecorateSymbolName() is not thread safe!
517  //Skip the first char
518  size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
519  if (size)
520  {
521  return result;
522  }
523  return name;
524 #else
525  int status;
526  char* result =
527  abi::__cxa_demangle(name, 0, 0, &status);
528  String sResult = result;
529  free(result);
530  return (status == 0) ? sResult : name;
531 #endif
532  }
533 
570  String DataType::customTypeName(bool demangle) const {
571  if (!demangle) return m_customTypeName;
572  return _demangleTypeName(m_customTypeName.c_str());
573  }
574 
582  String DataType::customTypeName2(bool demangle) const {
583  if (!demangle) return m_customTypeName2;
584  return _demangleTypeName(m_customTypeName2.c_str());
585  }
586 
601  const String id = internalID();
602  auto itAllocFn = m_allocFns.find(id);
603  assert(itAllocFn != m_allocFns.end());
604  const std::function<Object(Archive*)>& allocFn = itAllocFn->second;
605  return allocFn(archive);
606  }
607 
608  // *************** Member ***************
609  // *
610 
624  m_uid = NO_UID;
625  m_offset = 0;
626  m_parentUID = NO_UID;
627  }
628 
629  Member::Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent) {
630  m_name = name;
631  m_uid = uid;
632  m_offset = offset;
633  m_type = type;
634  m_parentUID = parent.uid();
635  }
636 
651  UID Member::uid() const {
652  return m_uid;
653  }
654 
663  return m_parentUID;
664  }
665 
687  return m_name;
688  }
689 
731  ssize_t Member::offset() const {
732  return m_offset;
733  }
734 
739  const DataType& Member::type() const {
740  return m_type;
741  }
742 
753  bool Member::isValid() const {
754  return m_uid && !m_name.empty() && m_type;
755  }
756 
765  bool Member::operator==(const Member& other) const {
766  return m_uid == other.m_uid &&
767  m_offset == other.m_offset &&
768  m_name == other.m_name &&
769  m_type == other.m_type;
770  }
771 
777  bool Member::operator!=(const Member& other) const {
778  return !operator==(other);
779  }
780 
793  bool Member::operator<(const Member& other) const {
794  return m_uid < other.m_uid ||
795  (m_uid == other.m_uid &&
796  (m_offset < other.m_offset ||
797  (m_offset == other.m_offset &&
798  (m_name < other.m_name ||
799  (m_name == other.m_name &&
800  m_type < other.m_type)))));
801  }
802 
815  bool Member::operator>(const Member& other) const {
816  return !(operator==(other) || operator<(other));
817  }
818 
819  // *************** Object ***************
820  // *
821 
834  m_parentUID = NO_UID;
835  m_version = 0;
836  m_minVersion = 0;
837  }
838 
856  Object::Object(UIDChain uidChain, DataType type, const Object& parent) {
857  m_type = type;
858  m_uid = uidChain;
859  m_parentUID = parent.uid();
860  m_version = 0;
861  m_minVersion = 0;
862  //m_data.resize(type.size());
863  }
864 
875  bool Object::isValid() const {
876  return m_type && !m_uid.empty();
877  }
878 
890  UID Object::uid(int index) const {
891  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
892  }
893 
907  return m_parentUID;
908  }
909 
910  static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
911  if (type.isPointer()) {
912  // assuming hex encoding
913  uintptr_t addr = std::stoull(s, NULL, 16);
914  *(void**)ptr = reinterpret_cast<void*>(addr);
915  } else if (type.isPrimitive()) {
916  if (type.isInteger() || type.isEnum()) {
917  if (type.isSigned()) {
918  if (type.size() == 1)
919  *(int8_t*)ptr = (int8_t) atoll(s);
920  else if (type.size() == 2)
921  *(int16_t*)ptr = (int16_t) atoll(s);
922  else if (type.size() == 4)
923  *(int32_t*)ptr = (int32_t) atoll(s);
924  else if (type.size() == 8)
925  *(int64_t*)ptr = (int64_t) atoll(s);
926  else
927  assert(false /* unknown signed int type size */);
928  } else {
929  if (type.size() == 1)
930  *(uint8_t*)ptr = (uint8_t) atoll(s);
931  else if (type.size() == 2)
932  *(uint16_t*)ptr = (uint16_t) atoll(s);
933  else if (type.size() == 4)
934  *(uint32_t*)ptr = (uint32_t) atoll(s);
935  else if (type.size() == 8)
936  *(uint64_t*)ptr = (uint64_t) atoll(s);
937  else
938  assert(false /* unknown unsigned int type size */);
939  }
940  } else if (type.isReal()) {
941  if (type.size() == sizeof(float))
942  *(float*)ptr = (float) atof(s);
943  else if (type.size() == sizeof(double))
944  *(double*)ptr = (double) atof(s);
945  else
946  assert(false /* unknown floating point type */);
947  } else if (type.isBool()) {
948  String lower = toLowerCase(s);
949  const bool b = lower != "0" && lower != "false" && lower != "no";
950  *(bool*)ptr = b;
951  } else if (type.isString()) {
952  *(String*)ptr = s;
953  } else {
954  assert(false /* no built-in cast from string support for this data type */);
955  }
956  }
957  }
958 
975  const ID& id = uid().id;
976  void* ptr = (void*)id;
977  _setNativeValueFromString(ptr, m_type, s.c_str());
978  }
979 
986  const UIDChain& Object::uidChain() const {
987  return m_uid;
988  }
989 
995  const DataType& Object::type() const {
996  return m_type;
997  }
998 
1021  const RawData& Object::rawData() const {
1022  return m_data;
1023  }
1024 
1036  return m_version;
1037  }
1038 
1051  return m_minVersion;
1052  }
1053 
1086  std::vector<Member>& Object::members() {
1087  return m_members;
1088  }
1089 
1096  const std::vector<Member>& Object::members() const {
1097  return m_members;
1098  }
1099 
1110  bool Object::operator==(const Object& other) const {
1111  // ignoring all other member variables here
1112  // (since UID stands for "unique" ;-) )
1113  return m_uid == other.m_uid &&
1114  m_type == other.m_type;
1115  }
1116 
1122  bool Object::operator!=(const Object& other) const {
1123  return !operator==(other);
1124  }
1125 
1138  bool Object::operator<(const Object& other) const {
1139  // ignoring all other member variables here
1140  // (since UID stands for "unique" ;-) )
1141  return m_uid < other.m_uid ||
1142  (m_uid == other.m_uid &&
1143  m_type < other.m_type);
1144  }
1145 
1158  bool Object::operator>(const Object& other) const {
1159  return !(operator==(other) || operator<(other));
1160  }
1161 
1180  bool Object::isVersionCompatibleTo(const Object& other) const {
1181  if (this->version() == other.version())
1182  return true;
1183  if (this->version() > other.version())
1184  return this->minVersion() <= other.version();
1185  else
1186  return other.minVersion() <= this->version();
1187  }
1188 
1189  void Object::setVersion(Version v) {
1190  m_version = v;
1191  }
1192 
1193  void Object::setMinVersion(Version v) {
1194  m_minVersion = v;
1195  }
1196 
1227  for (int i = 0; i < m_members.size(); ++i)
1228  if (m_members[i].name() == name)
1229  return m_members[i];
1230  return Member();
1231  }
1232 
1247  Member Object::memberByUID(const UID& uid) const {
1248  if (!uid) return Member();
1249  for (int i = 0; i < m_members.size(); ++i)
1250  if (m_members[i].uid() == uid)
1251  return m_members[i];
1252  return Member();
1253  }
1254 
1255  void Object::remove(const Member& member) {
1256  for (int i = 0; i < m_members.size(); ++i) {
1257  if (m_members[i] == member) {
1258  m_members.erase(m_members.begin() + i);
1259  return;
1260  }
1261  }
1262  }
1263 
1279  std::vector<Member> Object::membersOfType(const DataType& type) const {
1280  std::vector<Member> v;
1281  for (int i = 0; i < m_members.size(); ++i) {
1282  const Member& member = m_members[i];
1283  if (member.type() == type)
1284  v.push_back(member);
1285  }
1286  return v;
1287  }
1288 
1320  int Object::sequenceIndexOf(const Member& member) const {
1321  for (int i = 0; i < m_members.size(); ++i)
1322  if (m_members[i] == member)
1323  return i;
1324  return -1;
1325  }
1326 
1327  // *************** Archive ***************
1328  // *
1329 
1349  m_operation = OPERATION_NONE;
1350  m_root = NO_UID;
1351  m_isModified = false;
1352  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1353  }
1354 
1370  Archive::Archive(const RawData& data) {
1371  m_operation = OPERATION_NONE;
1372  m_root = NO_UID;
1373  m_isModified = false;
1374  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1375  decode(data);
1376  }
1377 
1398  Archive::Archive(const uint8_t* data, size_t size) {
1399  m_operation = OPERATION_NONE;
1400  m_root = NO_UID;
1401  m_isModified = false;
1402  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1403  decode(data, size);
1404  }
1405 
1406  Archive::~Archive() {
1407  }
1408 
1420  return m_allObjects[m_root];
1421  }
1422 
1423  static String _encodeBlob(String data) {
1424  return ToString(data.length()) + ":" + data;
1425  }
1426 
1427  static String _encode(const UID& uid) {
1428  String s;
1429  s += _encodeBlob(ToString(size_t(uid.id)));
1430  s += _encodeBlob(ToString(size_t(uid.size)));
1431  return _encodeBlob(s);
1432  }
1433 
1434  static String _encode(const time_t& time) {
1435  return _encodeBlob(ToString(time));
1436  }
1437 
1438  static String _encode(const DataType& type) {
1439  String s;
1440 
1441  // Srx v1.0 format (mandatory):
1442  s += _encodeBlob(type.baseTypeName());
1443  s += _encodeBlob(type.customTypeName());
1444  s += _encodeBlob(ToString(type.size()));
1445  s += _encodeBlob(ToString(type.isPointer()));
1446 
1447  // Srx v1.1 format:
1448  s += _encodeBlob(type.customTypeName2());
1449 
1450  return _encodeBlob(s);
1451  }
1452 
1453  static String _encode(const UIDChain& chain) {
1454  String s;
1455  for (int i = 0; i < chain.size(); ++i)
1456  s += _encode(chain[i]);
1457  return _encodeBlob(s);
1458  }
1459 
1460  static String _encode(const Member& member) {
1461  String s;
1462  s += _encode(member.uid());
1463  s += _encodeBlob(ToString(member.offset()));
1464  s += _encodeBlob(member.name());
1465  s += _encode(member.type());
1466  return _encodeBlob(s);
1467  }
1468 
1469  static String _encode(const std::vector<Member>& members) {
1470  String s;
1471  for (int i = 0; i < members.size(); ++i)
1472  s += _encode(members[i]);
1473  return _encodeBlob(s);
1474  }
1475 
1476  static String _primitiveObjectValueToString(const Object& obj) {
1477  String s;
1478  const DataType& type = obj.type();
1479  const ID& id = obj.uid().id;
1480  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1481  if (!obj.m_data.empty())
1482  assert(type.size() == obj.m_data.size());
1483  if (type.isPrimitive() && !type.isPointer()) {
1484  if (type.isInteger() || type.isEnum()) {
1485  if (type.isSigned()) {
1486  if (type.size() == 1)
1487  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1488  else if (type.size() == 2)
1489  s = ToString(*(int16_t*)ptr);
1490  else if (type.size() == 4)
1491  s = ToString(*(int32_t*)ptr);
1492  else if (type.size() == 8)
1493  s = ToString(*(int64_t*)ptr);
1494  else
1495  assert(false /* unknown signed int type size */);
1496  } else {
1497  if (type.size() == 1)
1498  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1499  else if (type.size() == 2)
1500  s = ToString(*(uint16_t*)ptr);
1501  else if (type.size() == 4)
1502  s = ToString(*(uint32_t*)ptr);
1503  else if (type.size() == 8)
1504  s = ToString(*(uint64_t*)ptr);
1505  else
1506  assert(false /* unknown unsigned int type size */);
1507  }
1508  } else if (type.isReal()) {
1509  if (type.size() == sizeof(float))
1510  s = ToString(*(float*)ptr);
1511  else if (type.size() == sizeof(double))
1512  s = ToString(*(double*)ptr);
1513  else
1514  assert(false /* unknown floating point type */);
1515  } else if (type.isBool()) {
1516  s = ToString(*(bool*)ptr);
1517  } else if (type.isString()) {
1518  s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1519  } else {
1520  assert(false /* unknown primitive type */);
1521  }
1522  }
1523  return s;
1524  }
1525 
1526  template<typename T>
1527  inline T _stringToNumber(const String& s) {
1528  assert(false /* String cast to unknown primitive number type */);
1529  }
1530 
1531  template<>
1532  inline int64_t _stringToNumber(const String& s) {
1533  return atoll(s.c_str());
1534  }
1535 
1536  template<>
1537  inline double _stringToNumber(const String& s) {
1538  return atof(s.c_str());
1539  }
1540 
1541  template<>
1542  inline bool _stringToNumber(const String& s) {
1543  return (bool) atoll(s.c_str());
1544  }
1545 
1546  template<typename T>
1547  static T _primitiveObjectValueToNumber(const Object& obj) {
1548  T value = 0;
1549  const DataType& type = obj.type();
1550  const ID& id = obj.uid().id;
1551  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1552  if (!obj.m_data.empty())
1553  assert(type.size() == obj.m_data.size());
1554  if (type.isPrimitive() && !type.isPointer()) {
1555  if (type.isInteger() || type.isEnum()) {
1556  if (type.isSigned()) {
1557  if (type.size() == 1)
1558  value = (T)*(int8_t*)ptr;
1559  else if (type.size() == 2)
1560  value = (T)*(int16_t*)ptr;
1561  else if (type.size() == 4)
1562  value = (T)*(int32_t*)ptr;
1563  else if (type.size() == 8)
1564  value = (T)*(int64_t*)ptr;
1565  else
1566  assert(false /* unknown signed int type size */);
1567  } else {
1568  if (type.size() == 1)
1569  value = (T)*(uint8_t*)ptr;
1570  else if (type.size() == 2)
1571  value = (T)*(uint16_t*)ptr;
1572  else if (type.size() == 4)
1573  value = (T)*(uint32_t*)ptr;
1574  else if (type.size() == 8)
1575  value = (T)*(uint64_t*)ptr;
1576  else
1577  assert(false /* unknown unsigned int type size */);
1578  }
1579  } else if (type.isReal()) {
1580  if (type.size() == sizeof(float))
1581  value = (T)*(float*)ptr;
1582  else if (type.size() == sizeof(double))
1583  value = (T)*(double*)ptr;
1584  else
1585  assert(false /* unknown floating point type */);
1586  } else if (type.isBool()) {
1587  value = (T)*(bool*)ptr;
1588  } else if (type.isString()) {
1589  value = _stringToNumber<T>(
1590  obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1591  );
1592  } else {
1593  assert(false /* unknown primitive type */);
1594  }
1595  }
1596  return value;
1597  }
1598 
1599  static String _encodePrimitiveValue(const Object& obj) {
1600  return _encodeBlob( _primitiveObjectValueToString(obj) );
1601  }
1602 
1603  static String _encode(const Object& obj) {
1604  String s;
1605  s += _encode(obj.type());
1606  s += _encodeBlob(ToString(obj.version()));
1607  s += _encodeBlob(ToString(obj.minVersion()));
1608  s += _encode(obj.uidChain());
1609  s += _encode(obj.members());
1610  s += _encodePrimitiveValue(obj);
1611  // Srx v1.2 format:
1612  s += _encode(obj.parentUID());
1613 
1614  return _encodeBlob(s);
1615  }
1616 
1617  String _encode(const Archive::ObjectPool& objects) {
1618  String s;
1619  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1620  itObject != objects.end(); ++itObject)
1621  {
1622  const Object& obj = itObject->second;
1623  s += _encode(obj);
1624  }
1625  return _encodeBlob(s);
1626  }
1627 
1628  /*
1629  * Srx format history:
1630  * - 1.0: Initial version.
1631  * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1632  * 2nd custom type name (e.g. "Map" types which always contain two
1633  * user defined types).
1634  * - 1.2: Stores objects' parent UID, which projects which native data
1635  * structure was contained within the boundaries of which specific
1636  * other data structure. This permits to automatically restore native
1637  * pointers, as structured layout info is required to identify
1638  * whether a pointer was just a "weak" pointer or a "strong" pointer.
1639  * For a "strong" pointer the pointed data has to be allocated
1640  * automatically by this framework, whereas for "weak" pointers not.
1641  */
1642  #define MAGIC_START "Srx1v"
1643  #define ENCODING_FORMAT_MINOR_VERSION 2
1644 
1645  String Archive::_encodeRootBlob() {
1646  String s;
1647  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1648  s += _encode(m_root);
1649  s += _encode(m_allObjects);
1650  s += _encodeBlob(m_name);
1651  s += _encodeBlob(m_comment);
1652  s += _encode(m_timeCreated);
1653  s += _encode(m_timeModified);
1654  return _encodeBlob(s);
1655  }
1656 
1657  void Archive::encode() {
1658  m_rawData.clear();
1659  String s = MAGIC_START;
1660  m_timeModified = time(NULL);
1661  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1662  m_timeCreated = m_timeModified;
1663  s += _encodeRootBlob();
1664  m_rawData.resize(s.length() + 1);
1665  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1666  m_isModified = false;
1667  }
1668 
1669  struct _Blob {
1670  const char* p;
1671  const char* end;
1672  };
1673 
1674  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1675  if (!bThrow && p >= end) {
1676  const _Blob blob = { p, end };
1677  return blob;
1678  }
1679  size_t sz = 0;
1680  for (; true; ++p) {
1681  if (p >= end)
1682  throw Exception("Decode Error: Missing blob");
1683  const char& c = *p;
1684  if (c == ':') break;
1685  if (c < '0' || c > '9')
1686  throw Exception("Decode Error: Missing blob size");
1687  sz *= 10;
1688  sz += size_t(c - '0');
1689  }
1690  ++p;
1691  if (p + sz > end)
1692  throw Exception("Decode Error: Premature end of blob");
1693  const _Blob blob = { p, p + sz };
1694  return blob;
1695  }
1696 
1697  template<typename T_int>
1698  static T_int _popIntBlob(const char*& p, const char* end) {
1699  _Blob blob = _decodeBlob(p, end);
1700  p = blob.p;
1701  end = blob.end;
1702 
1703  T_int sign = 1;
1704  T_int i = 0;
1705  if (p >= end)
1706  throw Exception("Decode Error: premature end of int blob");
1707  if (*p == '-') {
1708  sign = -1;
1709  ++p;
1710  }
1711  for (; p < end; ++p) {
1712  const char& c = *p;
1713  if (c < '0' || c > '9')
1714  throw Exception("Decode Error: Invalid int blob format");
1715  i *= 10;
1716  i += size_t(c - '0');
1717  }
1718  return i * sign;
1719  }
1720 
1721  template<typename T_int>
1722  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1723  const T_int i = _popIntBlob<T_int>(p, end);
1724  *(T_int*)&rawData[0] = i;
1725  }
1726 
1727  template<typename T_real>
1728  static T_real _popRealBlob(const char*& p, const char* end) {
1729  _Blob blob = _decodeBlob(p, end);
1730  p = blob.p;
1731  end = blob.end;
1732 
1733  if (p >= end || (end - p) < 1)
1734  throw Exception("Decode Error: premature end of real blob");
1735 
1736  String s(p, size_t(end - p));
1737 
1738  T_real r;
1739  if (sizeof(T_real) <= sizeof(double))
1740  r = atof(s.c_str());
1741  else
1742  assert(false /* unknown real type */);
1743 
1744  p += s.length();
1745 
1746  return r;
1747  }
1748 
1749  template<typename T_real>
1750  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1751  const T_real r = _popRealBlob<T_real>(p, end);
1752  *(T_real*)&rawData[0] = r;
1753  }
1754 
1755  static String _popStringBlob(const char*& p, const char* end) {
1756  _Blob blob = _decodeBlob(p, end);
1757  p = blob.p;
1758  end = blob.end;
1759  if (end - p < 0)
1760  throw Exception("Decode Error: missing String blob");
1761  String s;
1762  const size_t sz = end - p;
1763  s.resize(sz);
1764  memcpy(&s[0], p, sz);
1765  p += sz;
1766  return s;
1767  }
1768 
1769  static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1770  String s = _popStringBlob(p, end);
1771  rawData.resize(s.length() + 1);
1772  strcpy((char*)&rawData[0], &s[0]);
1773  }
1774 
1775  static time_t _popTimeBlob(const char*& p, const char* end) {
1776  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1777  return (time_t) i;
1778  }
1779 
1780  static DataType _popDataTypeBlob(const char*& p, const char* end) {
1781  _Blob blob = _decodeBlob(p, end);
1782  p = blob.p;
1783  end = blob.end;
1784 
1785  DataType type;
1786 
1787  // Srx v1.0 format (mandatory):
1788  type.m_baseTypeName = _popStringBlob(p, end);
1789  type.m_customTypeName = _popStringBlob(p, end);
1790  type.m_size = _popIntBlob<int>(p, end);
1791  type.m_isPointer = _popIntBlob<bool>(p, end);
1792 
1793  // Srx v1.1 format (optional):
1794  if (p < end)
1795  type.m_customTypeName2 = _popStringBlob(p, end);
1796 
1797  return type;
1798  }
1799 
1800  static UID _popUIDBlob(const char*& p, const char* end) {
1801  _Blob blob = _decodeBlob(p, end);
1802  p = blob.p;
1803  end = blob.end;
1804 
1805  if (p >= end)
1806  throw Exception("Decode Error: premature end of UID blob");
1807 
1808  const ID id = (ID) _popIntBlob<size_t>(p, end);
1809  const size_t size = _popIntBlob<size_t>(p, end);
1810 
1811  const UID uid = { id, size };
1812  return uid;
1813  }
1814 
1815  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1816  _Blob blob = _decodeBlob(p, end);
1817  p = blob.p;
1818  end = blob.end;
1819 
1820  UIDChain chain;
1821  while (p < end) {
1822  const UID uid = _popUIDBlob(p, end);
1823  chain.push_back(uid);
1824  }
1825  assert(!chain.empty());
1826  return chain;
1827  }
1828 
1829  static Member _popMemberBlob(const char*& p, const char* end) {
1830  _Blob blob = _decodeBlob(p, end, false);
1831  p = blob.p;
1832  end = blob.end;
1833 
1834  Member m;
1835  if (p >= end) return m;
1836 
1837  m.m_uid = _popUIDBlob(p, end);
1838  m.m_offset = _popIntBlob<ssize_t>(p, end);
1839  m.m_name = _popStringBlob(p, end);
1840  m.m_type = _popDataTypeBlob(p, end);
1841  assert(m.type());
1842  assert(!m.name().empty());
1843  assert(m.uid().isValid());
1844  return m;
1845  }
1846 
1847  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1848  _Blob blob = _decodeBlob(p, end, false);
1849  p = blob.p;
1850  end = blob.end;
1851 
1852  std::vector<Member> members;
1853  while (p < end) {
1854  const Member member = _popMemberBlob(p, end);
1855  if (member)
1856  members.push_back(member);
1857  else
1858  break;
1859  }
1860  return members;
1861  }
1862 
1863  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1864  const DataType& type = obj.type();
1865  if (type.isPrimitive() && !type.isPointer()) {
1866  obj.m_data.resize(type.size());
1867  if (type.isInteger() || type.isEnum()) {
1868  if (type.isSigned()) {
1869  if (type.size() == 1)
1870  _popIntBlob<int8_t>(p, end, obj.m_data);
1871  else if (type.size() == 2)
1872  _popIntBlob<int16_t>(p, end, obj.m_data);
1873  else if (type.size() == 4)
1874  _popIntBlob<int32_t>(p, end, obj.m_data);
1875  else if (type.size() == 8)
1876  _popIntBlob<int64_t>(p, end, obj.m_data);
1877  else
1878  assert(false /* unknown signed int type size */);
1879  } else {
1880  if (type.size() == 1)
1881  _popIntBlob<uint8_t>(p, end, obj.m_data);
1882  else if (type.size() == 2)
1883  _popIntBlob<uint16_t>(p, end, obj.m_data);
1884  else if (type.size() == 4)
1885  _popIntBlob<uint32_t>(p, end, obj.m_data);
1886  else if (type.size() == 8)
1887  _popIntBlob<uint64_t>(p, end, obj.m_data);
1888  else
1889  assert(false /* unknown unsigned int type size */);
1890  }
1891  } else if (type.isReal()) {
1892  if (type.size() == sizeof(float))
1893  _popRealBlob<float>(p, end, obj.m_data);
1894  else if (type.size() == sizeof(double))
1895  _popRealBlob<double>(p, end, obj.m_data);
1896  else
1897  assert(false /* unknown floating point type */);
1898  } else if (type.isBool()) {
1899  _popIntBlob<uint8_t>(p, end, obj.m_data);
1900  } else if (type.isString()) {
1901  _popStringBlob(p, end, obj.m_data);
1902  } else {
1903  assert(false /* unknown primitive type */);
1904  }
1905 
1906  } else {
1907  // don't whine if the empty blob was not added on encoder side
1908  _Blob blob = _decodeBlob(p, end, false);
1909  p = blob.p;
1910  end = blob.end;
1911  }
1912  }
1913 
1914  static Object _popObjectBlob(const char*& p, const char* end) {
1915  _Blob blob = _decodeBlob(p, end, false);
1916  p = blob.p;
1917  end = blob.end;
1918 
1919  Object obj;
1920  if (p >= end) return obj;
1921 
1922  obj.m_type = _popDataTypeBlob(p, end);
1923  obj.m_version = _popIntBlob<Version>(p, end);
1924  obj.m_minVersion = _popIntBlob<Version>(p, end);
1925  obj.m_uid = _popUIDChainBlob(p, end);
1926  obj.m_members = _popMembersBlob(p, end);
1927  _popPrimitiveValue(p, end, obj);
1928  assert(obj.type());
1929 
1930  // Srx v1.2 format (optional):
1931  if (p < end)
1932  obj.m_parentUID = _popUIDBlob(p, end);
1933 
1934  return obj;
1935  }
1936 
1937  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1938  _Blob blob = _decodeBlob(p, end, false);
1939  p = blob.p;
1940  end = blob.end;
1941 
1942  if (p >= end)
1943  throw Exception("Decode Error: Premature end of objects blob");
1944 
1945  while (true) {
1946  const Object obj = _popObjectBlob(p, end);
1947  if (!obj) break;
1948  m_allObjects[obj.uid()] = obj;
1949  }
1950  }
1951 
1952  void Archive::_popRootBlob(const char*& p, const char* end) {
1953  _Blob blob = _decodeBlob(p, end, false);
1954  p = blob.p;
1955  end = blob.end;
1956 
1957  if (p >= end)
1958  throw Exception("Decode Error: Premature end of root blob");
1959 
1960  // just in case this encoding format will be extended in future
1961  // (currently not used)
1962  const int formatMinorVersion = _popIntBlob<int>(p, end);
1963 
1964  m_root = _popUIDBlob(p, end);
1965  if (!m_root)
1966  throw Exception("Decode Error: No root object");
1967 
1968  _popObjectsBlob(p, end);
1969  if (!m_allObjects[m_root])
1970  throw Exception("Decode Error: Missing declared root object");
1971 
1972  m_name = _popStringBlob(p, end);
1973  m_comment = _popStringBlob(p, end);
1974  m_timeCreated = _popTimeBlob(p, end);
1975  m_timeModified = _popTimeBlob(p, end);
1976  }
1977 
1993  void Archive::decode(const RawData& data) {
1994  m_rawData = data;
1995  m_allObjects.clear();
1996  m_isModified = false;
1997  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1998  const char* p = (const char*) &data[0];
1999  const char* end = p + data.size();
2000  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
2001  throw Exception("Decode Error: Magic start missing!");
2002  p += strlen(MAGIC_START);
2003  _popRootBlob(p, end);
2004  }
2005 
2026  void Archive::decode(const uint8_t* data, size_t size) {
2027  RawData rawData;
2028  rawData.resize(size);
2029  memcpy(&rawData[0], data, size);
2030  decode(rawData);
2031  }
2032 
2049  if (m_isModified) encode();
2050  return m_rawData;
2051  }
2052 
2059  return MAGIC_START;
2060  }
2061 
2076  bool Archive::isModified() const {
2077  return m_isModified;
2078  }
2079 
2086  m_allObjects.clear();
2087  m_operation = OPERATION_NONE;
2088  m_root = NO_UID;
2089  m_rawData.clear();
2090  m_isModified = false;
2091  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2092  }
2093 
2102  return m_name;
2103  }
2104 
2115  if (m_name == name) return;
2116  m_name = name;
2117  m_isModified = true;
2118  }
2119 
2128  return m_comment;
2129  }
2130 
2140  void Archive::setComment(String comment) {
2141  if (m_comment == comment) return;
2142  m_comment = comment;
2143  m_isModified = true;
2144  }
2145 
2146  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2147  tm* pTm;
2148  switch (base) {
2149  case LOCAL_TIME:
2150  pTm = localtime(&time);
2151  break;
2152  case UTC_TIME:
2153  pTm = gmtime(&time);
2154  break;
2155  default:
2156  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2157  }
2158  if (!pTm)
2159  throw Exception("Failed assembling time stamp structure");
2160  return *pTm;
2161  }
2162 
2168  time_t Archive::timeStampCreated() const {
2169  return m_timeCreated;
2170  }
2171 
2178  return m_timeModified;
2179  }
2180 
2192  return _convertTimeStamp(m_timeCreated, base);
2193  }
2194 
2206  return _convertTimeStamp(m_timeModified, base);
2207  }
2208 
2226  void Archive::removeMember(Object& parent, const Member& member) {
2227  parent.remove(member);
2228  m_isModified = true;
2229  }
2230 
2246  void Archive::remove(const Object& obj) {
2247  //FIXME: Should traverse from root object and remove all members associated with this object
2248  if (!obj.uid()) return;
2249  m_allObjects.erase(obj.uid());
2250  m_isModified = true;
2251  }
2252 
2265  return m_allObjects[uid];
2266  }
2267 
2277  return m_allObjects[obj.parentUID()];
2278  }
2279 
2286  return m_allObjects[member.parentUID()];
2287  }
2288 
2300  if (!object) return;
2301  object.setVersion(v);
2302  m_isModified = true;
2303  }
2304 
2316  if (!object) return;
2317  object.setMinVersion(v);
2318  m_isModified = true;
2319  }
2320 
2329  void Archive::setEnumValue(Object& object, uint64_t value) {
2330  if (!object) return;
2331  if (!object.type().isEnum())
2332  throw Exception("Not an enum data type");
2333  Object* pObject = &object;
2334  if (object.type().isPointer()) {
2335  Object& obj = objectByUID(object.uid(1));
2336  if (!obj) return;
2337  pObject = &obj;
2338  }
2339  const int nativeEnumSize = sizeof(enum operation_t);
2340  DataType& type = const_cast<DataType&>( pObject->type() );
2341  // original serializer ("sender") might have had a different word size
2342  // than this machine, adjust type object in this case
2343  if (type.size() != nativeEnumSize) {
2344  type.m_size = nativeEnumSize;
2345  }
2346  pObject->m_data.resize(type.size());
2347  void* ptr = &pObject->m_data[0];
2348  if (type.size() == 1)
2349  *(uint8_t*)ptr = (uint8_t)value;
2350  else if (type.size() == 2)
2351  *(uint16_t*)ptr = (uint16_t)value;
2352  else if (type.size() == 4)
2353  *(uint32_t*)ptr = (uint32_t)value;
2354  else if (type.size() == 8)
2355  *(uint64_t*)ptr = (uint64_t)value;
2356  else
2357  assert(false /* unknown enum type size */);
2358  m_isModified = true;
2359  }
2360 
2371  void Archive::setIntValue(Object& object, int64_t value) {
2372  if (!object) return;
2373  if (!object.type().isInteger())
2374  throw Exception("Not an integer data type");
2375  Object* pObject = &object;
2376  if (object.type().isPointer()) {
2377  Object& obj = objectByUID(object.uid(1));
2378  if (!obj) return;
2379  pObject = &obj;
2380  }
2381  const DataType& type = pObject->type();
2382  pObject->m_data.resize(type.size());
2383  void* ptr = &pObject->m_data[0];
2384  if (type.isSigned()) {
2385  if (type.size() == 1)
2386  *(int8_t*)ptr = (int8_t)value;
2387  else if (type.size() == 2)
2388  *(int16_t*)ptr = (int16_t)value;
2389  else if (type.size() == 4)
2390  *(int32_t*)ptr = (int32_t)value;
2391  else if (type.size() == 8)
2392  *(int64_t*)ptr = (int64_t)value;
2393  else
2394  assert(false /* unknown signed int type size */);
2395  } else {
2396  if (type.size() == 1)
2397  *(uint8_t*)ptr = (uint8_t)value;
2398  else if (type.size() == 2)
2399  *(uint16_t*)ptr = (uint16_t)value;
2400  else if (type.size() == 4)
2401  *(uint32_t*)ptr = (uint32_t)value;
2402  else if (type.size() == 8)
2403  *(uint64_t*)ptr = (uint64_t)value;
2404  else
2405  assert(false /* unknown unsigned int type size */);
2406  }
2407  m_isModified = true;
2408  }
2409 
2421  void Archive::setRealValue(Object& object, double value) {
2422  if (!object) return;
2423  if (!object.type().isReal())
2424  throw Exception("Not a real data type");
2425  Object* pObject = &object;
2426  if (object.type().isPointer()) {
2427  Object& obj = objectByUID(object.uid(1));
2428  if (!obj) return;
2429  pObject = &obj;
2430  }
2431  const DataType& type = pObject->type();
2432  pObject->m_data.resize(type.size());
2433  void* ptr = &pObject->m_data[0];
2434  if (type.size() == sizeof(float))
2435  *(float*)ptr = (float)value;
2436  else if (type.size() == sizeof(double))
2437  *(double*)ptr = (double)value;
2438  else
2439  assert(false /* unknown real type size */);
2440  m_isModified = true;
2441  }
2442 
2451  void Archive::setBoolValue(Object& object, bool value) {
2452  if (!object) return;
2453  if (!object.type().isBool())
2454  throw Exception("Not a bool data type");
2455  Object* pObject = &object;
2456  if (object.type().isPointer()) {
2457  Object& obj = objectByUID(object.uid(1));
2458  if (!obj) return;
2459  pObject = &obj;
2460  }
2461  const DataType& type = pObject->type();
2462  pObject->m_data.resize(type.size());
2463  bool* ptr = (bool*)&pObject->m_data[0];
2464  *ptr = value;
2465  m_isModified = true;
2466  }
2467 
2476  void Archive::setStringValue(Object& object, String value) {
2477  if (!object) return;
2478  if (!object.type().isString())
2479  throw Exception("Not a String data type");
2480  Object* pObject = &object;
2481  if (object.type().isPointer()) {
2482  Object& obj = objectByUID(object.uid(1));
2483  if (!obj) return;
2484  pObject = &obj;
2485  }
2486  pObject->m_data.resize(value.length() + 1);
2487  char* ptr = (char*) &pObject->m_data[0];
2488  strcpy(ptr, &value[0]);
2489  m_isModified = true;
2490  }
2491 
2505  void Archive::setAutoValue(Object& object, String value) {
2506  if (!object) return;
2507  const DataType& type = object.type();
2508  if (type.isInteger())
2509  setIntValue(object, atoll(value.c_str()));
2510  else if (type.isReal())
2511  setRealValue(object, atof(value.c_str()));
2512  else if (type.isBool()) {
2513  String val = toLowerCase(value);
2514  if (val == "true" || val == "yes" || val == "1")
2515  setBoolValue(object, true);
2516  else if (val == "false" || val == "no" || val == "0")
2517  setBoolValue(object, false);
2518  else
2519  setBoolValue(object, atof(value.c_str()));
2520  } else if (type.isString())
2521  setStringValue(object, value);
2522  else if (type.isEnum())
2523  setEnumValue(object, atoll(value.c_str()));
2524  else
2525  throw Exception("Not a primitive data type");
2526  }
2527 
2538  if (!object)
2539  throw Exception("Invalid object");
2540  if (object.type().isClass())
2541  throw Exception("Object is class type");
2542  const Object* pObject = &object;
2543  if (object.type().isPointer()) {
2544  const Object& obj = objectByUID(object.uid(1));
2545  if (!obj) return "";
2546  pObject = &obj;
2547  }
2548  return _primitiveObjectValueToString(*pObject);
2549  }
2550 
2560  int64_t Archive::valueAsInt(const Object& object) {
2561  if (!object)
2562  throw Exception("Invalid object");
2563  if (!object.type().isInteger() && !object.type().isEnum())
2564  throw Exception("Object is neither an integer nor an enum");
2565  const Object* pObject = &object;
2566  if (object.type().isPointer()) {
2567  const Object& obj = objectByUID(object.uid(1));
2568  if (!obj) return 0;
2569  pObject = &obj;
2570  }
2571  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2572  }
2573 
2583  double Archive::valueAsReal(const Object& object) {
2584  if (!object)
2585  throw Exception("Invalid object");
2586  if (!object.type().isReal())
2587  throw Exception("Object is not an real type");
2588  const Object* pObject = &object;
2589  if (object.type().isPointer()) {
2590  const Object& obj = objectByUID(object.uid(1));
2591  if (!obj) return 0;
2592  pObject = &obj;
2593  }
2594  return _primitiveObjectValueToNumber<double>(*pObject);
2595  }
2596 
2605  bool Archive::valueAsBool(const Object& object) {
2606  if (!object)
2607  throw Exception("Invalid object");
2608  if (!object.type().isBool())
2609  throw Exception("Object is not a bool");
2610  const Object* pObject = &object;
2611  if (object.type().isPointer()) {
2612  const Object& obj = objectByUID(object.uid(1));
2613  if (!obj) return 0;
2614  pObject = &obj;
2615  }
2616  return _primitiveObjectValueToNumber<bool>(*pObject);
2617  }
2618 
2619  Archive::operation_t Archive::operation() const {
2620  return m_operation;
2621  }
2622 
2623  // *************** Archive::Syncer ***************
2624  // *
2625 
2626  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2627  : m_dst(dst), m_src(src)
2628  {
2629  const Object srcRootObj = src.rootObject();
2630  const Object dstRootObj = dst.rootObject();
2631  if (!srcRootObj)
2632  throw Exception("No source root object!");
2633  if (!dstRootObj)
2634  throw Exception("Expected destination root object not found!");
2635  syncObject(dstRootObj, srcRootObj);
2636  }
2637 
2638  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2639  assert(srcObj.rawData().size() == dstObj.type().size());
2640  void* pDst = (void*)dstObj.uid().id;
2641  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2642  }
2643 
2644  void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2645  assert(dstObj.type().isString());
2646  assert(dstObj.type() == srcObj.type());
2647  String* pDst = (String*)(void*)dstObj.uid().id;
2648  *pDst = (String) (const char*) &srcObj.rawData()[0];
2649  }
2650 
2651  void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2652  assert(dstObj.type().isArray());
2653  assert(dstObj.type() == srcObj.type());
2654  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2655  }
2656 
2657  void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2658  assert(dstObj.type().isSet());
2659  assert(dstObj.type() == srcObj.type());
2660  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2661  }
2662 
2663  void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2664  assert(dstObj.type().isMap());
2665  assert(dstObj.type() == srcObj.type());
2666  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2667  }
2668 
2669  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2670  assert(dstObj.type().isPointer());
2671  assert(dstObj.type() == srcObj.type());
2672  void** ppDst = (void**)dstObj.uid().id;
2673  if (!srcObj.uid(1)) { // NULL pointer on source side ...
2674  *ppDst = NULL;
2675  return;
2676  }
2677  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2678  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2679  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
2680  assert(uidRelation != m_counterparts.end());
2681  const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2682  assert(pointedDstObject);
2683  *ppDst = (void*)pointedDstObject.uid().id;
2684  } else { // "strong" pointer to object, allocation required ...
2685  assert(pointedSrcObject.type());
2686  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2687  assert(pointedDstObject);
2688 
2689  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2690  *ppDst = (void*)pointedDstObject.uid().id;
2691  syncObject(pointedDstObject, pointedSrcObject);
2692  }
2693  }
2694 
2695  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2696  assert(dstObj && srcObj);
2697 
2698  // remember UID mapping between source and destination side
2699  //
2700  // As UIDs differ between source archive side and destination archive
2701  // side (as UIDs always translate to native data's real memory address),
2702  // remember their relationship, such that we can later on translate
2703  // objects from source archive side correctly to objects on destination
2704  // side, which is required to sync native pointers correctly for
2705  // pointing to respective correct, real memory address.
2706  const bool alreadySynced =
2707  !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2708 
2709  // Prevent syncing this object again, and thus also prevent endless
2710  // loop on data structures with cyclic relations.
2711  if (alreadySynced)
2712  return; // end of recursion
2713 
2714  if (!dstObj.isVersionCompatibleTo(srcObj))
2715  throw Exception("Version incompatible (destination version " +
2716  ToString(dstObj.version()) + " [min. version " +
2717  ToString(dstObj.minVersion()) + "], source version " +
2718  ToString(srcObj.version()) + " [min. version " +
2719  ToString(srcObj.minVersion()) + "])");
2720  if (dstObj.type() != srcObj.type())
2721  throw Exception("Incompatible data structure type (destination type " +
2722  dstObj.type().asLongDescr() + " vs. source type " +
2723  srcObj.type().asLongDescr() + ")");
2724 
2725  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2726  if (dstObj.type().isString())
2727  syncString(dstObj, srcObj);
2728  else
2729  syncPrimitive(dstObj, srcObj);
2730  return; // end of recursion
2731  }
2732 
2733  if (dstObj.type().isArray()) {
2734  syncArray(dstObj, srcObj);
2735  return;
2736  }
2737 
2738  if (dstObj.type().isSet()) {
2739  syncSet(dstObj, srcObj);
2740  return;
2741  }
2742 
2743  if (dstObj.type().isMap()) {
2744  syncMap(dstObj, srcObj);
2745  return;
2746  }
2747 
2748  if (dstObj.type().isPointer()) {
2749  syncPointer(dstObj, srcObj);
2750  return;
2751  }
2752 
2753  assert(dstObj.type().isClass());
2754  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2755  const Member& srcMember = srcObj.members()[iMember];
2756  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2757  if (!dstMember)
2758  throw Exception("Expected member missing in destination object");
2759  syncMember(dstMember, srcMember);
2760  }
2761  }
2762 
2763  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2764  Member dstMember = dstObj.memberNamed(srcMember.name());
2765  if (dstMember)
2766  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2767  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2768  if (members.size() <= 0)
2769  return Member();
2770  if (members.size() == 1)
2771  return members[0];
2772  for (int i = 0; i < members.size(); ++i)
2773  if (members[i].offset() == srcMember.offset())
2774  return members[i];
2775  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2776  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2777  for (int i = 0; i < members.size(); ++i) {
2778  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2779  if (dstSeqNr == srcSeqNr)
2780  return members[i];
2781  }
2782  return Member(); // give up!
2783  }
2784 
2785  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2786  assert(dstMember && srcMember);
2787  assert(dstMember.type() == srcMember.type());
2788  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2789  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2790  syncObject(dstObj, srcObj);
2791  }
2792 
2793  // *************** Exception ***************
2794  // *
2795 
2796  Exception::Exception() {
2797  }
2798 
2799  Exception::Exception(String format, ...) {
2800  va_list arg;
2801  va_start(arg, format);
2802  Message = assemble(format, arg);
2803  va_end(arg);
2804  }
2805 
2806  Exception::Exception(String format, va_list arg) {
2807  Message = assemble(format, arg);
2808  }
2809 
2816  std::cout << "Serialization::Exception: " << Message << std::endl;
2817  }
2818 
2819  String Exception::assemble(String format, va_list arg) {
2820  char* buf = NULL;
2821  vasprintf(&buf, format.c_str(), arg);
2822  String s = buf;
2823  free(buf);
2824  return s;
2825  }
2826 
2827 } // namespace Serialization
Destination container for serialization, and source container for deserialization.
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
Object & parentObjectOf(const Object &obj)
Access parent of supplied object.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
String internalID() const
Unique key for native data type, for internal purposes only.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Object newInstance(Archive *archive) const
Allocate and initialize a native instance of data type.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage() const
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
UID parentUID() const
Unique identifier of parent object.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
UID parentUID() const
Unique identifier of parent object.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
Definition: gig.h:98
void * ID
Abstract identifier for serialized C++ objects.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
std::string String
Textual string.
uint32_t Version
Version number data type.
std::vector< UID > UIDChain
Chain of UIDs.
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
time_base_t
To which time zone a certain timing information relates to.
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...