libgig  4.5.0.svn11
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 <cstdint> // for uintptr_t
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  // *************** UID ***************
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 
84  std::map<String,DataType::NativeType> DataType::m_nativeTypes;
85 
96  m_size = 0;
97  m_isPointer = false;
98  }
99 
127  DataType::DataType(bool isPointer, int size, String baseType,
128  String customType1, String customType2)
129  {
130  m_size = size;
131  m_isPointer = isPointer;
132  m_baseTypeName = baseType;
133  m_customTypeName = customType1;
134  m_customTypeName2 = customType2;
135  }
136 
147  bool DataType::isValid() const {
148  return m_size;
149  }
150 
156  bool DataType::isPointer() const {
157  return m_isPointer;
158  }
159 
185  bool DataType::isClass() const {
186  return m_baseTypeName == "class";
187  }
188 
209  bool DataType::isPrimitive() const {
210  return !isClass() && !isArray() && !isSet() && !isMap();
211  }
212 
223  bool DataType::isString() const {
224  return m_baseTypeName == "String";
225  }
226 
241  bool DataType::isInteger() const {
242  return m_baseTypeName.substr(0, 3) == "int" ||
243  m_baseTypeName.substr(0, 4) == "uint";
244  }
245 
258  bool DataType::isReal() const {
259  return m_baseTypeName.substr(0, 4) == "real";
260  }
261 
273  bool DataType::isBool() const {
274  return m_baseTypeName == "bool";
275  }
276 
288  bool DataType::isEnum() const {
289  return m_baseTypeName == "enum";
290  }
291 
304  bool DataType::isArray() const {
305  return m_baseTypeName == "Array";
306  }
307 
320  bool DataType::isSet() const {
321  return m_baseTypeName == "Set";
322  }
323 
336  bool DataType::isMap() const {
337  return m_baseTypeName == "Map";
338  }
339 
353  bool DataType::isSigned() const {
354  return m_baseTypeName.substr(0, 3) == "int" ||
355  isReal();
356  }
357 
376  bool DataType::operator==(const DataType& other) const {
377  return m_baseTypeName == other.m_baseTypeName &&
378  m_customTypeName == other.m_customTypeName &&
379  m_customTypeName2 == other.m_customTypeName2 &&
380  (m_size == other.m_size || (isClass() && other.isClass())) &&
381  m_isPointer == other.m_isPointer;
382  }
383 
397  return m_baseTypeName + "," +
398  m_customTypeName + "," +
399  m_customTypeName2 + "," +
400  ToString(isClass()) + "," +
401  ToString(m_isPointer);
402  }
403 
409  bool DataType::operator!=(const DataType& other) const {
410  return !operator==(other);
411  }
412 
424  bool DataType::operator<(const DataType& other) const {
425  return m_baseTypeName < other.m_baseTypeName ||
426  (m_baseTypeName == other.m_baseTypeName &&
427  (m_customTypeName < other.m_customTypeName ||
428  (m_customTypeName == other.m_customTypeName &&
429  (m_customTypeName2 < other.m_customTypeName2 ||
430  (m_customTypeName2 == other.m_customTypeName2 &&
431  (m_size < other.m_size ||
432  (m_size == other.m_size &&
433  m_isPointer < other.m_isPointer)))))));
434  }
435 
447  bool DataType::operator>(const DataType& other) const {
448  return !(operator==(other) || operator<(other));
449  }
450 
466  String s = m_baseTypeName;
467  if (!m_customTypeName.empty())
468  s += " " + customTypeName(true);
469  if (!m_customTypeName2.empty())
470  s += " " + customTypeName2(true);
471  if (isPointer())
472  s += " pointer";
473  return s;
474  }
475 
506  return m_baseTypeName;
507  }
508 
509  static String _demangleTypeName(const char* name) {
510 #ifdef _MSC_VER
511  const size_t MAXLENGTH = 1024;
512  char result[MAXLENGTH];
513 
514  //FIXME: calling UnDecorateSymbolName() is not thread safe!
515  //Skip the first char
516  size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
517  if (size)
518  {
519  return result;
520  }
521  return name;
522 #else
523  int status;
524  char* result =
525  abi::__cxa_demangle(name, 0, 0, &status);
526  String sResult = result;
527  free(result);
528  return (status == 0) ? sResult : name;
529 #endif
530  }
531 
568  String DataType::customTypeName(bool demangle) const {
569  if (!demangle) return m_customTypeName;
570  return _demangleTypeName(m_customTypeName.c_str());
571  }
572 
580  String DataType::customTypeName2(bool demangle) const {
581  if (!demangle) return m_customTypeName2;
582  return _demangleTypeName(m_customTypeName2.c_str());
583  }
584 
599  const String id = internalID();
600  auto itNativeType = m_nativeTypes.find(id);
601  if (itNativeType == m_nativeTypes.end()) {
602  fprintf(stderr,
603  "(De)serialization Failure: cannot create new instance of "
604  "unknown data type '%s' !\n",
605  asLongDescr().c_str());
606  assert(false && "You may need to explicitly register this data "
607  "type by either calling "
608  "DataType::registerNativeType<T>() or using class "
609  "NativeDataTypeRegistry");
610  }
611  const std::function<Object(Archive*)>& allocFn = itNativeType->second.allocFn;
612  return allocFn(archive);
613  }
614 
615  // *************** Member ***************
616  // *
617 
631  m_uid = NO_UID;
632  m_offset = 0;
633  m_parentUID = NO_UID;
634  }
635 
636  Member::Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent) {
637  m_name = name;
638  m_uid = uid;
639  m_offset = offset;
640  m_type = type;
641  m_parentUID = parent.uid();
642  }
643 
658  UID Member::uid() const {
659  return m_uid;
660  }
661 
670  return m_parentUID;
671  }
672 
694  return m_name;
695  }
696 
738  ssize_t Member::offset() const {
739  return m_offset;
740  }
741 
746  const DataType& Member::type() const {
747  return m_type;
748  }
749 
760  bool Member::isValid() const {
761  return m_uid && !m_name.empty() && m_type;
762  }
763 
772  bool Member::operator==(const Member& other) const {
773  return m_uid == other.m_uid &&
774  m_offset == other.m_offset &&
775  m_name == other.m_name &&
776  m_type == other.m_type;
777  }
778 
784  bool Member::operator!=(const Member& other) const {
785  return !operator==(other);
786  }
787 
800  bool Member::operator<(const Member& other) const {
801  return m_uid < other.m_uid ||
802  (m_uid == other.m_uid &&
803  (m_offset < other.m_offset ||
804  (m_offset == other.m_offset &&
805  (m_name < other.m_name ||
806  (m_name == other.m_name &&
807  m_type < other.m_type)))));
808  }
809 
822  bool Member::operator>(const Member& other) const {
823  return !(operator==(other) || operator<(other));
824  }
825 
826  // *************** Object ***************
827  // *
828 
841  m_parentUID = NO_UID;
842  m_version = 0;
843  m_minVersion = 0;
844  }
845 
863  Object::Object(UIDChain uidChain, DataType type, const Object& parent) {
864  m_type = type;
865  m_uid = uidChain;
866  m_parentUID = parent.uid();
867  m_version = 0;
868  m_minVersion = 0;
869  //m_data.resize(type.size());
870  }
871 
882  bool Object::isValid() const {
883  return m_type && !m_uid.empty();
884  }
885 
897  UID Object::uid(int index) const {
898  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
899  }
900 
914  return m_parentUID;
915  }
916 
917  static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
918  if (type.isPointer()) {
919  // assuming hex encoding
920  uintptr_t addr = std::stoull(s, NULL, 16);
921  *(void**)ptr = reinterpret_cast<void*>(addr);
922  } else if (type.isPrimitive()) {
923  if (type.isInteger() || type.isEnum()) {
924  if (type.isSigned()) {
925  if (type.size() == 1)
926  *(int8_t*)ptr = strTo<int8_t>(s);
927  else if (type.size() == 2)
928  *(int16_t*)ptr = strTo<int16_t>(s);
929  else if (type.size() == 4)
930  *(int32_t*)ptr = strTo<int32_t>(s);
931  else if (type.size() == 8)
932  *(int64_t*)ptr = strTo<int64_t>(s);
933  else
934  assert(false /* unknown signed int type size */);
935  } else {
936  if (type.size() == 1)
937  *(uint8_t*)ptr = strTo<uint8_t>(s);
938  else if (type.size() == 2)
939  *(uint16_t*)ptr = strTo<uint16_t>(s);
940  else if (type.size() == 4)
941  *(uint32_t*)ptr = strTo<uint32_t>(s);
942  else if (type.size() == 8)
943  *(uint64_t*)ptr = strTo<uint64_t>(s);
944  else
945  assert(false /* unknown unsigned int type size */);
946  }
947  } else if (type.isReal()) {
948  if (type.size() == sizeof(float))
949  *(float*)ptr = strTo<float>(s);
950  else if (type.size() == sizeof(double))
951  *(double*)ptr = strTo<double>(s);
952  else
953  assert(false /* unknown floating point type */);
954  } else if (type.isBool()) {
955  String lower = toLowerCase(s);
956  const bool b = lower != "0" && lower != "false" && lower != "no";
957  *(bool*)ptr = b;
958  } else if (type.isString()) {
959  *(String*)ptr = s;
960  } else {
961  assert(false /* no built-in cast from string support for this data type */);
962  }
963  }
964  }
965 
982  const ID& id = uid().id;
983  void* ptr = (void*)id;
984  _setNativeValueFromString(ptr, m_type, s.c_str());
985  }
986 
993  const UIDChain& Object::uidChain() const {
994  return m_uid;
995  }
996 
1002  const DataType& Object::type() const {
1003  return m_type;
1004  }
1005 
1028  const RawData& Object::rawData() const {
1029  return m_data;
1030  }
1031 
1043  return m_version;
1044  }
1045 
1058  return m_minVersion;
1059  }
1060 
1093  std::vector<Member>& Object::members() {
1094  return m_members;
1095  }
1096 
1103  const std::vector<Member>& Object::members() const {
1104  return m_members;
1105  }
1106 
1117  bool Object::operator==(const Object& other) const {
1118  // ignoring all other member variables here
1119  // (since UID stands for "unique" ;-) )
1120  return m_uid == other.m_uid &&
1121  m_type == other.m_type;
1122  }
1123 
1129  bool Object::operator!=(const Object& other) const {
1130  return !operator==(other);
1131  }
1132 
1145  bool Object::operator<(const Object& other) const {
1146  // ignoring all other member variables here
1147  // (since UID stands for "unique" ;-) )
1148  return m_uid < other.m_uid ||
1149  (m_uid == other.m_uid &&
1150  m_type < other.m_type);
1151  }
1152 
1165  bool Object::operator>(const Object& other) const {
1166  return !(operator==(other) || operator<(other));
1167  }
1168 
1187  bool Object::isVersionCompatibleTo(const Object& other) const {
1188  if (this->version() == other.version())
1189  return true;
1190  if (this->version() > other.version())
1191  return this->minVersion() <= other.version();
1192  else
1193  return other.minVersion() <= this->version();
1194  }
1195 
1196  void Object::setVersion(Version v) {
1197  m_version = v;
1198  }
1199 
1200  void Object::setMinVersion(Version v) {
1201  m_minVersion = v;
1202  }
1203 
1234  for (int i = 0; i < m_members.size(); ++i)
1235  if (m_members[i].name() == name)
1236  return m_members[i];
1237  return Member();
1238  }
1239 
1254  Member Object::memberByUID(const UID& uid) const {
1255  if (!uid) return Member();
1256  for (int i = 0; i < m_members.size(); ++i)
1257  if (m_members[i].uid() == uid)
1258  return m_members[i];
1259  return Member();
1260  }
1261 
1262  void Object::remove(const Member& member) {
1263  for (int i = 0; i < m_members.size(); ++i) {
1264  if (m_members[i] == member) {
1265  m_members.erase(m_members.begin() + i);
1266  return;
1267  }
1268  }
1269  }
1270 
1286  std::vector<Member> Object::membersOfType(const DataType& type) const {
1287  std::vector<Member> v;
1288  for (int i = 0; i < m_members.size(); ++i) {
1289  const Member& member = m_members[i];
1290  if (member.type() == type)
1291  v.push_back(member);
1292  }
1293  return v;
1294  }
1295 
1327  int Object::sequenceIndexOf(const Member& member) const {
1328  for (int i = 0; i < m_members.size(); ++i)
1329  if (m_members[i] == member)
1330  return i;
1331  return -1;
1332  }
1333 
1334  // *************** Archive ***************
1335  // *
1336 
1356  m_operation = OPERATION_NONE;
1357  m_root = NO_UID;
1358  m_isModified = false;
1359  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1360  }
1361 
1377  Archive::Archive(const RawData& data) {
1378  m_operation = OPERATION_NONE;
1379  m_root = NO_UID;
1380  m_isModified = false;
1381  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1382  decode(data);
1383  }
1384 
1405  Archive::Archive(const uint8_t* data, size_t size) {
1406  m_operation = OPERATION_NONE;
1407  m_root = NO_UID;
1408  m_isModified = false;
1409  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1410  decode(data, size);
1411  }
1412 
1413  Archive::~Archive() {
1414  }
1415 
1427  return m_allObjects[m_root];
1428  }
1429 
1430  static String _encodeBlob(String data) {
1431  return ToString(data.length()) + ":" + data;
1432  }
1433 
1434  static String _encode(const UID& uid) {
1435  String s;
1436  s += _encodeBlob(ToString(size_t(uid.id)));
1437  s += _encodeBlob(ToString(size_t(uid.size)));
1438  return _encodeBlob(s);
1439  }
1440 
1441  static String _encode(const time_t& time) {
1442  return _encodeBlob(ToString(time));
1443  }
1444 
1445  static String _encode(const DataType& type) {
1446  String s;
1447 
1448  // Srx v1.0 format (mandatory):
1449  s += _encodeBlob(type.baseTypeName());
1450  s += _encodeBlob(type.customTypeName());
1451  s += _encodeBlob(ToString(type.size()));
1452  s += _encodeBlob(ToString(type.isPointer()));
1453 
1454  // Srx v1.1 format:
1455  s += _encodeBlob(type.customTypeName2());
1456 
1457  return _encodeBlob(s);
1458  }
1459 
1460  static String _encode(const UIDChain& chain) {
1461  String s;
1462  for (int i = 0; i < chain.size(); ++i)
1463  s += _encode(chain[i]);
1464  return _encodeBlob(s);
1465  }
1466 
1467  static String _encode(const Member& member) {
1468  String s;
1469  s += _encode(member.uid());
1470  s += _encodeBlob(ToString(member.offset()));
1471  s += _encodeBlob(member.name());
1472  s += _encode(member.type());
1473  return _encodeBlob(s);
1474  }
1475 
1476  static String _encode(const std::vector<Member>& members) {
1477  String s;
1478  for (int i = 0; i < members.size(); ++i)
1479  s += _encode(members[i]);
1480  return _encodeBlob(s);
1481  }
1482 
1483  static String _primitiveObjectValueToString(const Object& obj) {
1484  String s;
1485  const DataType& type = obj.type();
1486  const ID& id = obj.uid().id;
1487  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1488  if (!obj.m_data.empty())
1489  assert(type.size() == obj.m_data.size());
1490  if (type.isPrimitive() && !type.isPointer()) {
1491  if (type.isInteger() || type.isEnum()) {
1492  if (type.isSigned()) {
1493  if (type.size() == 1)
1494  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1495  else if (type.size() == 2)
1496  s = ToString(*(int16_t*)ptr);
1497  else if (type.size() == 4)
1498  s = ToString(*(int32_t*)ptr);
1499  else if (type.size() == 8)
1500  s = ToString(*(int64_t*)ptr);
1501  else
1502  assert(false /* unknown signed int type size */);
1503  } else {
1504  if (type.size() == 1)
1505  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1506  else if (type.size() == 2)
1507  s = ToString(*(uint16_t*)ptr);
1508  else if (type.size() == 4)
1509  s = ToString(*(uint32_t*)ptr);
1510  else if (type.size() == 8)
1511  s = ToString(*(uint64_t*)ptr);
1512  else
1513  assert(false /* unknown unsigned int type size */);
1514  }
1515  } else if (type.isReal()) {
1516  if (type.size() == sizeof(float))
1517  s = ToString(*(float*)ptr);
1518  else if (type.size() == sizeof(double))
1519  s = ToString(*(double*)ptr);
1520  else
1521  assert(false /* unknown floating point type */);
1522  } else if (type.isBool()) {
1523  s = ToString(*(bool*)ptr);
1524  } else if (type.isString()) {
1525  s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1526  } else {
1527  assert(false /* unknown primitive type */);
1528  }
1529  }
1530  return s;
1531  }
1532 
1533  template<typename T>
1534  inline T _stringToNumber(const String& s) {
1535  assert(false /* String cast to unknown primitive number type */);
1536  }
1537 
1538  template<>
1539  inline int64_t _stringToNumber(const String& s) {
1540  return strTo<int64_t>(s);
1541  }
1542 
1543  template<>
1544  inline double _stringToNumber(const String& s) {
1545  return strTo<double>(s);
1546  }
1547 
1548  template<>
1549  inline bool _stringToNumber(const String& s) {
1550  return strTo<bool>(s);
1551  }
1552 
1553  template<typename T>
1554  static T _primitiveObjectValueToNumber(const Object& obj) {
1555  T value = 0;
1556  const DataType& type = obj.type();
1557  const ID& id = obj.uid().id;
1558  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1559  if (!obj.m_data.empty())
1560  assert(type.size() == obj.m_data.size());
1561  if (type.isPrimitive() && !type.isPointer()) {
1562  if (type.isInteger() || type.isEnum()) {
1563  if (type.isSigned()) {
1564  if (type.size() == 1)
1565  value = (T)*(int8_t*)ptr;
1566  else if (type.size() == 2)
1567  value = (T)*(int16_t*)ptr;
1568  else if (type.size() == 4)
1569  value = (T)*(int32_t*)ptr;
1570  else if (type.size() == 8)
1571  value = (T)*(int64_t*)ptr;
1572  else
1573  assert(false /* unknown signed int type size */);
1574  } else {
1575  if (type.size() == 1)
1576  value = (T)*(uint8_t*)ptr;
1577  else if (type.size() == 2)
1578  value = (T)*(uint16_t*)ptr;
1579  else if (type.size() == 4)
1580  value = (T)*(uint32_t*)ptr;
1581  else if (type.size() == 8)
1582  value = (T)*(uint64_t*)ptr;
1583  else
1584  assert(false /* unknown unsigned int type size */);
1585  }
1586  } else if (type.isReal()) {
1587  if (type.size() == sizeof(float))
1588  value = (T)*(float*)ptr;
1589  else if (type.size() == sizeof(double))
1590  value = (T)*(double*)ptr;
1591  else
1592  assert(false /* unknown floating point type */);
1593  } else if (type.isBool()) {
1594  value = (T)*(bool*)ptr;
1595  } else if (type.isString()) {
1596  value = _stringToNumber<T>(
1597  obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1598  );
1599  } else {
1600  assert(false /* unknown primitive type */);
1601  }
1602  }
1603  return value;
1604  }
1605 
1606  static String _encodePrimitiveValue(const Object& obj) {
1607  return _encodeBlob( _primitiveObjectValueToString(obj) );
1608  }
1609 
1610  static String _encode(const Object& obj) {
1611  String s;
1612  s += _encode(obj.type());
1613  s += _encodeBlob(ToString(obj.version()));
1614  s += _encodeBlob(ToString(obj.minVersion()));
1615  s += _encode(obj.uidChain());
1616  s += _encode(obj.members());
1617  s += _encodePrimitiveValue(obj);
1618  // Srx v1.2 format:
1619  s += _encode(obj.parentUID());
1620 
1621  return _encodeBlob(s);
1622  }
1623 
1624  String _encode(const Archive::ObjectPool& objects) {
1625  String s;
1626  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1627  itObject != objects.end(); ++itObject)
1628  {
1629  const Object& obj = itObject->second;
1630  s += _encode(obj);
1631  }
1632  return _encodeBlob(s);
1633  }
1634 
1635  /*
1636  * Srx format history:
1637  * - 1.0: Initial version.
1638  * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1639  * 2nd custom type name (e.g. "Map" types which always contain two
1640  * user defined types).
1641  * - 1.2: Stores objects' parent UID, which projects which native data
1642  * structure was contained within the boundaries of which specific
1643  * other data structure. This permits to automatically restore native
1644  * pointers, as structured layout info is required to identify
1645  * whether a pointer was just a "weak" pointer or a "strong" pointer.
1646  * For a "strong" pointer the pointed data has to be allocated
1647  * automatically by this framework, whereas for "weak" pointers not.
1648  */
1649  #define MAGIC_START "Srx1v"
1650  #define ENCODING_FORMAT_MINOR_VERSION 2
1651 
1652  String Archive::_encodeRootBlob() {
1653  String s;
1654  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1655  s += _encode(m_root);
1656  s += _encode(m_allObjects);
1657  s += _encodeBlob(m_name);
1658  s += _encodeBlob(m_comment);
1659  s += _encode(m_timeCreated);
1660  s += _encode(m_timeModified);
1661  return _encodeBlob(s);
1662  }
1663 
1664  void Archive::encode() {
1665  m_rawData.clear();
1666  String s = MAGIC_START;
1667  m_timeModified = time(NULL);
1668  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1669  m_timeCreated = m_timeModified;
1670  s += _encodeRootBlob();
1671  m_rawData.resize(s.length() + 1);
1672  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1673  m_isModified = false;
1674  }
1675 
1676  struct _Blob {
1677  const char* p;
1678  const char* end;
1679  };
1680 
1681  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1682  if (!bThrow && p >= end) {
1683  const _Blob blob = { p, end };
1684  return blob;
1685  }
1686  size_t sz = 0;
1687  for (; true; ++p) {
1688  if (p >= end)
1689  throw Exception("Decode Error: Missing blob");
1690  const char& c = *p;
1691  if (c == ':') break;
1692  if (c < '0' || c > '9')
1693  throw Exception("Decode Error: Missing blob size");
1694  sz *= 10;
1695  sz += size_t(c - '0');
1696  }
1697  ++p;
1698  if (p + sz > end)
1699  throw Exception("Decode Error: Premature end of blob");
1700  const _Blob blob = { p, p + sz };
1701  return blob;
1702  }
1703 
1704  template<typename T_int>
1705  static T_int _popIntBlob(const char*& p, const char* end) {
1706  _Blob blob = _decodeBlob(p, end);
1707  p = blob.p;
1708  end = blob.end;
1709 
1710  T_int sign = 1;
1711  T_int i = 0;
1712  if (p >= end)
1713  throw Exception("Decode Error: premature end of int blob");
1714  if (*p == '-') {
1715  sign = -1;
1716  ++p;
1717  }
1718  for (; p < end; ++p) {
1719  const char& c = *p;
1720  if (c < '0' || c > '9')
1721  throw Exception("Decode Error: Invalid int blob format");
1722  i *= 10;
1723  i += size_t(c - '0');
1724  }
1725  return i * sign;
1726  }
1727 
1728  template<typename T_int>
1729  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1730  const T_int i = _popIntBlob<T_int>(p, end);
1731  *(T_int*)&rawData[0] = i;
1732  }
1733 
1734  template<typename T_real>
1735  static T_real _popRealBlob(const char*& p, const char* end) {
1736  _Blob blob = _decodeBlob(p, end);
1737  p = blob.p;
1738  end = blob.end;
1739 
1740  if (p >= end || (end - p) < 1)
1741  throw Exception("Decode Error: premature end of real blob");
1742 
1743  String s(p, size_t(end - p));
1744 
1745  T_real r;
1746  if (sizeof(T_real) <= sizeof(double))
1747  r = strTo<T_real>(s);
1748  else
1749  assert(false /* unknown real type */);
1750 
1751  p += s.length();
1752 
1753  return r;
1754  }
1755 
1756  template<typename T_real>
1757  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1758  const T_real r = _popRealBlob<T_real>(p, end);
1759  *(T_real*)&rawData[0] = r;
1760  }
1761 
1762  static String _popStringBlob(const char*& p, const char* end) {
1763  _Blob blob = _decodeBlob(p, end);
1764  p = blob.p;
1765  end = blob.end;
1766  if (end - p < 0)
1767  throw Exception("Decode Error: missing String blob");
1768  String s;
1769  const size_t sz = end - p;
1770  s.resize(sz);
1771  memcpy(&s[0], p, sz);
1772  p += sz;
1773  return s;
1774  }
1775 
1776  static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1777  String s = _popStringBlob(p, end);
1778  rawData.resize(s.length() + 1);
1779  strcpy((char*)&rawData[0], &s[0]);
1780  }
1781 
1782  static time_t _popTimeBlob(const char*& p, const char* end) {
1783  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1784  return (time_t) i;
1785  }
1786 
1787  static DataType _popDataTypeBlob(const char*& p, const char* end) {
1788  _Blob blob = _decodeBlob(p, end);
1789  p = blob.p;
1790  end = blob.end;
1791 
1792  DataType type;
1793 
1794  // Srx v1.0 format (mandatory):
1795  type.m_baseTypeName = _popStringBlob(p, end);
1796  type.m_customTypeName = _popStringBlob(p, end);
1797  type.m_size = _popIntBlob<int>(p, end);
1798  type.m_isPointer = _popIntBlob<bool>(p, end);
1799 
1800  // Srx v1.1 format (optional):
1801  if (p < end)
1802  type.m_customTypeName2 = _popStringBlob(p, end);
1803 
1804  return type;
1805  }
1806 
1807  static UID _popUIDBlob(const char*& p, const char* end) {
1808  _Blob blob = _decodeBlob(p, end);
1809  p = blob.p;
1810  end = blob.end;
1811 
1812  if (p >= end)
1813  throw Exception("Decode Error: premature end of UID blob");
1814 
1815  const ID id = (ID) _popIntBlob<size_t>(p, end);
1816  const size_t size = _popIntBlob<size_t>(p, end);
1817 
1818  const UID uid = { id, size };
1819  return uid;
1820  }
1821 
1822  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1823  _Blob blob = _decodeBlob(p, end);
1824  p = blob.p;
1825  end = blob.end;
1826 
1827  UIDChain chain;
1828  while (p < end) {
1829  const UID uid = _popUIDBlob(p, end);
1830  chain.push_back(uid);
1831  }
1832  assert(!chain.empty());
1833  return chain;
1834  }
1835 
1836  static Member _popMemberBlob(const char*& p, const char* end) {
1837  _Blob blob = _decodeBlob(p, end, false);
1838  p = blob.p;
1839  end = blob.end;
1840 
1841  Member m;
1842  if (p >= end) return m;
1843 
1844  m.m_uid = _popUIDBlob(p, end);
1845  m.m_offset = _popIntBlob<ssize_t>(p, end);
1846  m.m_name = _popStringBlob(p, end);
1847  m.m_type = _popDataTypeBlob(p, end);
1848  assert(m.type());
1849  assert(!m.name().empty());
1850  assert(m.uid().isValid());
1851  return m;
1852  }
1853 
1854  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1855  _Blob blob = _decodeBlob(p, end, false);
1856  p = blob.p;
1857  end = blob.end;
1858 
1859  std::vector<Member> members;
1860  while (p < end) {
1861  const Member member = _popMemberBlob(p, end);
1862  if (member)
1863  members.push_back(member);
1864  else
1865  break;
1866  }
1867  return members;
1868  }
1869 
1870  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1871  const DataType& type = obj.type();
1872  if (type.isPrimitive() && !type.isPointer()) {
1873  obj.m_data.resize(type.size());
1874  if (type.isInteger() || type.isEnum()) {
1875  if (type.isSigned()) {
1876  if (type.size() == 1)
1877  _popIntBlob<int8_t>(p, end, obj.m_data);
1878  else if (type.size() == 2)
1879  _popIntBlob<int16_t>(p, end, obj.m_data);
1880  else if (type.size() == 4)
1881  _popIntBlob<int32_t>(p, end, obj.m_data);
1882  else if (type.size() == 8)
1883  _popIntBlob<int64_t>(p, end, obj.m_data);
1884  else
1885  assert(false /* unknown signed int type size */);
1886  } else {
1887  if (type.size() == 1)
1888  _popIntBlob<uint8_t>(p, end, obj.m_data);
1889  else if (type.size() == 2)
1890  _popIntBlob<uint16_t>(p, end, obj.m_data);
1891  else if (type.size() == 4)
1892  _popIntBlob<uint32_t>(p, end, obj.m_data);
1893  else if (type.size() == 8)
1894  _popIntBlob<uint64_t>(p, end, obj.m_data);
1895  else
1896  assert(false /* unknown unsigned int type size */);
1897  }
1898  } else if (type.isReal()) {
1899  if (type.size() == sizeof(float))
1900  _popRealBlob<float>(p, end, obj.m_data);
1901  else if (type.size() == sizeof(double))
1902  _popRealBlob<double>(p, end, obj.m_data);
1903  else
1904  assert(false /* unknown floating point type */);
1905  } else if (type.isBool()) {
1906  _popIntBlob<uint8_t>(p, end, obj.m_data);
1907  } else if (type.isString()) {
1908  _popStringBlob(p, end, obj.m_data);
1909  } else {
1910  assert(false /* unknown primitive type */);
1911  }
1912 
1913  } else {
1914  // don't whine if the empty blob was not added on encoder side
1915  _Blob blob = _decodeBlob(p, end, false);
1916  p = blob.p;
1917  end = blob.end;
1918  }
1919  }
1920 
1921  static Object _popObjectBlob(const char*& p, const char* end) {
1922  _Blob blob = _decodeBlob(p, end, false);
1923  p = blob.p;
1924  end = blob.end;
1925 
1926  Object obj;
1927  if (p >= end) return obj;
1928 
1929  obj.m_type = _popDataTypeBlob(p, end);
1930  obj.m_version = _popIntBlob<Version>(p, end);
1931  obj.m_minVersion = _popIntBlob<Version>(p, end);
1932  obj.m_uid = _popUIDChainBlob(p, end);
1933  obj.m_members = _popMembersBlob(p, end);
1934  _popPrimitiveValue(p, end, obj);
1935  assert(obj.type());
1936 
1937  // Srx v1.2 format (optional):
1938  if (p < end)
1939  obj.m_parentUID = _popUIDBlob(p, end);
1940 
1941  return obj;
1942  }
1943 
1944  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1945  _Blob blob = _decodeBlob(p, end, false);
1946  p = blob.p;
1947  end = blob.end;
1948 
1949  if (p >= end)
1950  throw Exception("Decode Error: Premature end of objects blob");
1951 
1952  while (true) {
1953  const Object obj = _popObjectBlob(p, end);
1954  if (!obj) break;
1955  m_allObjects[obj.uid()] = obj;
1956  }
1957  }
1958 
1959  void Archive::_popRootBlob(const char*& p, const char* end) {
1960  _Blob blob = _decodeBlob(p, end, false);
1961  p = blob.p;
1962  end = blob.end;
1963 
1964  if (p >= end)
1965  throw Exception("Decode Error: Premature end of root blob");
1966 
1967  // just in case this encoding format will be extended in future
1968  // (currently not used)
1969  const int formatMinorVersion = _popIntBlob<int>(p, end);
1970 
1971  m_root = _popUIDBlob(p, end);
1972  if (!m_root)
1973  throw Exception("Decode Error: No root object");
1974 
1975  _popObjectsBlob(p, end);
1976  if (!m_allObjects[m_root])
1977  throw Exception("Decode Error: Missing declared root object");
1978 
1979  m_name = _popStringBlob(p, end);
1980  m_comment = _popStringBlob(p, end);
1981  m_timeCreated = _popTimeBlob(p, end);
1982  m_timeModified = _popTimeBlob(p, end);
1983  }
1984 
2000  void Archive::decode(const RawData& data) {
2001  m_rawData = data;
2002  m_allObjects.clear();
2003  m_isModified = false;
2004  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2005  const char* p = (const char*) &data[0];
2006  const char* end = p + data.size();
2007  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
2008  throw Exception("Decode Error: Magic start missing!");
2009  p += strlen(MAGIC_START);
2010  _popRootBlob(p, end);
2011  }
2012 
2033  void Archive::decode(const uint8_t* data, size_t size) {
2034  RawData rawData;
2035  rawData.resize(size);
2036  memcpy(&rawData[0], data, size);
2037  decode(rawData);
2038  }
2039 
2056  if (m_isModified) encode();
2057  return m_rawData;
2058  }
2059 
2066  return MAGIC_START;
2067  }
2068 
2083  bool Archive::isModified() const {
2084  return m_isModified;
2085  }
2086 
2093  m_allObjects.clear();
2094  m_operation = OPERATION_NONE;
2095  m_root = NO_UID;
2096  m_rawData.clear();
2097  m_isModified = false;
2098  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2099  }
2100 
2109  return m_name;
2110  }
2111 
2122  if (m_name == name) return;
2123  m_name = name;
2124  m_isModified = true;
2125  }
2126 
2135  return m_comment;
2136  }
2137 
2147  void Archive::setComment(String comment) {
2148  if (m_comment == comment) return;
2149  m_comment = comment;
2150  m_isModified = true;
2151  }
2152 
2153  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2154  tm* pTm;
2155  switch (base) {
2156  case LOCAL_TIME:
2157  pTm = localtime(&time);
2158  break;
2159  case UTC_TIME:
2160  pTm = gmtime(&time);
2161  break;
2162  default:
2163  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2164  }
2165  if (!pTm)
2166  throw Exception("Failed assembling time stamp structure");
2167  return *pTm;
2168  }
2169 
2175  time_t Archive::timeStampCreated() const {
2176  return m_timeCreated;
2177  }
2178 
2185  return m_timeModified;
2186  }
2187 
2199  return _convertTimeStamp(m_timeCreated, base);
2200  }
2201 
2213  return _convertTimeStamp(m_timeModified, base);
2214  }
2215 
2233  void Archive::removeMember(Object& parent, const Member& member) {
2234  parent.remove(member);
2235  m_isModified = true;
2236  }
2237 
2253  void Archive::remove(const Object& obj) {
2254  //FIXME: Should traverse from root object and remove all members associated with this object
2255  if (!obj.uid()) return;
2256  m_allObjects.erase(obj.uid());
2257  m_isModified = true;
2258  }
2259 
2273  return m_allObjects[uid];
2274  }
2275 
2291  ObjectPool::iterator it = m_allObjects.find(uid);
2292  if (it != m_allObjects.end())
2293  return it->second;
2294 
2295  // find all objects with the same ID (i.e. memory address) AND being
2296  // larger than expected by passed base UID
2297  std::map<size_t,UID> matches;
2298  for (const auto& it : m_allObjects)
2299  if (it.first.id == uid.id && it.first.size > uid.size)
2300  matches[it.first.size] = it.first;
2301 
2302  if (matches.empty())
2303  return ObjectPool::invalidObject();
2304 
2305  // return the next larger object found
2306  return m_allObjects[matches.begin()->second];
2307  }
2308 
2318  return m_allObjects[obj.parentUID()];
2319  }
2320 
2327  return m_allObjects[member.parentUID()];
2328  }
2329 
2341  if (!object) return;
2342  object.setVersion(v);
2343  m_isModified = true;
2344  }
2345 
2357  if (!object) return;
2358  object.setMinVersion(v);
2359  m_isModified = true;
2360  }
2361 
2370  void Archive::setEnumValue(Object& object, uint64_t value) {
2371  if (!object) return;
2372  if (!object.type().isEnum())
2373  throw Exception("Not an enum data type");
2374  Object* pObject = &object;
2375  if (object.type().isPointer()) {
2376  Object& obj = objectByUID(object.uid(1));
2377  if (!obj) return;
2378  pObject = &obj;
2379  }
2380  const int nativeEnumSize = sizeof(enum operation_t);
2381  DataType& type = const_cast<DataType&>( pObject->type() );
2382  // original serializer ("sender") might have had a different word size
2383  // than this machine, adjust type object in this case
2384  if (type.size() != nativeEnumSize) {
2385  type.m_size = nativeEnumSize;
2386  }
2387  pObject->m_data.resize(type.size());
2388  void* ptr = &pObject->m_data[0];
2389  if (type.size() == 1)
2390  *(uint8_t*)ptr = (uint8_t)value;
2391  else if (type.size() == 2)
2392  *(uint16_t*)ptr = (uint16_t)value;
2393  else if (type.size() == 4)
2394  *(uint32_t*)ptr = (uint32_t)value;
2395  else if (type.size() == 8)
2396  *(uint64_t*)ptr = (uint64_t)value;
2397  else
2398  assert(false /* unknown enum type size */);
2399  m_isModified = true;
2400  }
2401 
2412  void Archive::setIntValue(Object& object, int64_t value) {
2413  if (!object) return;
2414  if (!object.type().isInteger())
2415  throw Exception("Not an integer data type");
2416  Object* pObject = &object;
2417  if (object.type().isPointer()) {
2418  Object& obj = objectByUID(object.uid(1));
2419  if (!obj) return;
2420  pObject = &obj;
2421  }
2422  const DataType& type = pObject->type();
2423  pObject->m_data.resize(type.size());
2424  void* ptr = &pObject->m_data[0];
2425  if (type.isSigned()) {
2426  if (type.size() == 1)
2427  *(int8_t*)ptr = (int8_t)value;
2428  else if (type.size() == 2)
2429  *(int16_t*)ptr = (int16_t)value;
2430  else if (type.size() == 4)
2431  *(int32_t*)ptr = (int32_t)value;
2432  else if (type.size() == 8)
2433  *(int64_t*)ptr = (int64_t)value;
2434  else
2435  assert(false /* unknown signed int type size */);
2436  } else {
2437  if (type.size() == 1)
2438  *(uint8_t*)ptr = (uint8_t)value;
2439  else if (type.size() == 2)
2440  *(uint16_t*)ptr = (uint16_t)value;
2441  else if (type.size() == 4)
2442  *(uint32_t*)ptr = (uint32_t)value;
2443  else if (type.size() == 8)
2444  *(uint64_t*)ptr = (uint64_t)value;
2445  else
2446  assert(false /* unknown unsigned int type size */);
2447  }
2448  m_isModified = true;
2449  }
2450 
2462  void Archive::setRealValue(Object& object, double value) {
2463  if (!object) return;
2464  if (!object.type().isReal())
2465  throw Exception("Not a real data type");
2466  Object* pObject = &object;
2467  if (object.type().isPointer()) {
2468  Object& obj = objectByUID(object.uid(1));
2469  if (!obj) return;
2470  pObject = &obj;
2471  }
2472  const DataType& type = pObject->type();
2473  pObject->m_data.resize(type.size());
2474  void* ptr = &pObject->m_data[0];
2475  if (type.size() == sizeof(float))
2476  *(float*)ptr = (float)value;
2477  else if (type.size() == sizeof(double))
2478  *(double*)ptr = (double)value;
2479  else
2480  assert(false /* unknown real type size */);
2481  m_isModified = true;
2482  }
2483 
2492  void Archive::setBoolValue(Object& object, bool value) {
2493  if (!object) return;
2494  if (!object.type().isBool())
2495  throw Exception("Not a bool data type");
2496  Object* pObject = &object;
2497  if (object.type().isPointer()) {
2498  Object& obj = objectByUID(object.uid(1));
2499  if (!obj) return;
2500  pObject = &obj;
2501  }
2502  const DataType& type = pObject->type();
2503  pObject->m_data.resize(type.size());
2504  bool* ptr = (bool*)&pObject->m_data[0];
2505  *ptr = value;
2506  m_isModified = true;
2507  }
2508 
2517  void Archive::setStringValue(Object& object, String value) {
2518  if (!object) return;
2519  if (!object.type().isString())
2520  throw Exception("Not a String data type");
2521  Object* pObject = &object;
2522  if (object.type().isPointer()) {
2523  Object& obj = objectByUID(object.uid(1));
2524  if (!obj) return;
2525  pObject = &obj;
2526  }
2527  pObject->m_data.resize(value.length() + 1);
2528  char* ptr = (char*) &pObject->m_data[0];
2529  strcpy(ptr, &value[0]);
2530  m_isModified = true;
2531  }
2532 
2546  void Archive::setAutoValue(Object& object, String value) {
2547  if (!object) return;
2548  const DataType& type = object.type();
2549  if (type.isInteger())
2550  setIntValue(object, strTo<int64_t>(value));
2551  else if (type.isReal())
2552  setRealValue(object, strTo<double>(value));
2553  else if (type.isBool()) {
2554  String val = toLowerCase(value);
2555  if (val == "true" || val == "yes" || val == "1")
2556  setBoolValue(object, true);
2557  else if (val == "false" || val == "no" || val == "0")
2558  setBoolValue(object, false);
2559  else
2560  setBoolValue(object, strTo<bool>(value));
2561  } else if (type.isString())
2562  setStringValue(object, value);
2563  else if (type.isEnum())
2564  setEnumValue(object, strTo<uint64_t>(value));
2565  else
2566  throw Exception("Not a primitive data type");
2567  }
2568 
2579  if (!object)
2580  throw Exception("Invalid object");
2581  if (object.type().isClass())
2582  throw Exception("Object is class type");
2583  const Object* pObject = &object;
2584  if (object.type().isPointer()) {
2585  const Object& obj = objectByUID(object.uid(1));
2586  if (!obj) return "";
2587  pObject = &obj;
2588  }
2589  return _primitiveObjectValueToString(*pObject);
2590  }
2591 
2601  int64_t Archive::valueAsInt(const Object& object) {
2602  if (!object)
2603  throw Exception("Invalid object");
2604  if (!object.type().isInteger() && !object.type().isEnum())
2605  throw Exception("Object is neither an integer nor an enum");
2606  const Object* pObject = &object;
2607  if (object.type().isPointer()) {
2608  const Object& obj = objectByUID(object.uid(1));
2609  if (!obj) return 0;
2610  pObject = &obj;
2611  }
2612  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2613  }
2614 
2624  double Archive::valueAsReal(const Object& object) {
2625  if (!object)
2626  throw Exception("Invalid object");
2627  if (!object.type().isReal())
2628  throw Exception("Object is not an real type");
2629  const Object* pObject = &object;
2630  if (object.type().isPointer()) {
2631  const Object& obj = objectByUID(object.uid(1));
2632  if (!obj) return 0;
2633  pObject = &obj;
2634  }
2635  return _primitiveObjectValueToNumber<double>(*pObject);
2636  }
2637 
2646  bool Archive::valueAsBool(const Object& object) {
2647  if (!object)
2648  throw Exception("Invalid object");
2649  if (!object.type().isBool())
2650  throw Exception("Object is not a bool");
2651  const Object* pObject = &object;
2652  if (object.type().isPointer()) {
2653  const Object& obj = objectByUID(object.uid(1));
2654  if (!obj) return 0;
2655  pObject = &obj;
2656  }
2657  return _primitiveObjectValueToNumber<bool>(*pObject);
2658  }
2659 
2660  Archive::operation_t Archive::operation() const {
2661  return m_operation;
2662  }
2663 
2664  // *************** Archive::Syncer ***************
2665  // *
2666 
2667  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2668  : m_dst(dst), m_src(src)
2669  {
2670  const Object srcRootObj = src.rootObject();
2671  const Object dstRootObj = dst.rootObject();
2672  if (!srcRootObj)
2673  throw Exception("No source root object!");
2674  if (!dstRootObj)
2675  throw Exception("Expected destination root object not found!");
2676  syncObject(dstRootObj, srcRootObj);
2677  }
2678 
2679  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2680  assert(srcObj.rawData().size() == dstObj.type().size());
2681  void* pDst = (void*)dstObj.uid().id;
2682  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2683  }
2684 
2685  void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2686  assert(dstObj.type().isString());
2687  assert(dstObj.type() == srcObj.type());
2688  String* pDst = (String*)(void*)dstObj.uid().id;
2689  *pDst = (String) (const char*) &srcObj.rawData()[0];
2690  }
2691 
2692  void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2693  assert(dstObj.type().isArray());
2694  assert(dstObj.type() == srcObj.type());
2695  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2696  }
2697 
2698  void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2699  assert(dstObj.type().isSet());
2700  assert(dstObj.type() == srcObj.type());
2701  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2702  }
2703 
2704  void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2705  assert(dstObj.type().isMap());
2706  assert(dstObj.type() == srcObj.type());
2707  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2708  }
2709 
2710  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2711  assert(dstObj.type().isPointer());
2712  assert(dstObj.type() == srcObj.type());
2713  void** ppDst = (void**)dstObj.uid().id;
2714  if (!srcObj.uid(1)) { // NULL pointer on source side ...
2715  *ppDst = NULL;
2716  return;
2717  }
2718  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2719  assert(pointedSrcObject);
2720  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2721  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
2722  assert(uidRelation != m_counterparts.end());
2723  const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2724  assert(pointedDstObject);
2725  *ppDst = (void*)pointedDstObject.uid().id;
2726  } else { // "strong" pointer to object, allocation required ...
2727  assert(pointedSrcObject.type());
2728  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2729  assert(pointedDstObject);
2730 
2731  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2732  *ppDst = (void*)pointedDstObject.uid().id;
2733  syncObject(pointedDstObject, pointedSrcObject);
2734  }
2735  }
2736 
2737  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2738  assert(dstObj && srcObj);
2739 
2740  // remember UID mapping between source and destination side
2741  //
2742  // As UIDs differ between source archive side and destination archive
2743  // side (as UIDs always translate to native data's real memory address),
2744  // remember their relationship, such that we can later on translate
2745  // objects from source archive side correctly to objects on destination
2746  // side, which is required to sync native pointers correctly for
2747  // pointing to respective correct, real memory address.
2748  const bool alreadySynced =
2749  !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2750 
2751  // Prevent syncing this object again, and thus also prevent endless
2752  // loop on data structures with cyclic relations.
2753  if (alreadySynced)
2754  return; // end of recursion
2755 
2756  if (!dstObj.isVersionCompatibleTo(srcObj))
2757  throw Exception("Version incompatible (destination version " +
2758  ToString(dstObj.version()) + " [min. version " +
2759  ToString(dstObj.minVersion()) + "], source version " +
2760  ToString(srcObj.version()) + " [min. version " +
2761  ToString(srcObj.minVersion()) + "])");
2762  if (dstObj.type() != srcObj.type())
2763  throw Exception("Incompatible data structure type (destination type " +
2764  dstObj.type().asLongDescr() + " vs. source type " +
2765  srcObj.type().asLongDescr() + ")");
2766 
2767  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2768  if (dstObj.type().isString())
2769  syncString(dstObj, srcObj);
2770  else
2771  syncPrimitive(dstObj, srcObj);
2772  return; // end of recursion
2773  }
2774 
2775  if (dstObj.type().isArray()) {
2776  syncArray(dstObj, srcObj);
2777  return;
2778  }
2779 
2780  if (dstObj.type().isSet()) {
2781  syncSet(dstObj, srcObj);
2782  return;
2783  }
2784 
2785  if (dstObj.type().isMap()) {
2786  syncMap(dstObj, srcObj);
2787  return;
2788  }
2789 
2790  if (dstObj.type().isPointer()) {
2791  syncPointer(dstObj, srcObj);
2792  return;
2793  }
2794 
2795  assert(dstObj.type().isClass());
2796  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2797  const Member& srcMember = srcObj.members()[iMember];
2798  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2799  if (!dstMember)
2800  throw Exception("Expected member missing in destination object");
2801  syncMember(dstMember, srcMember);
2802  }
2803  }
2804 
2805  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2806  Member dstMember = dstObj.memberNamed(srcMember.name());
2807  if (dstMember)
2808  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2809  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2810  if (members.size() <= 0)
2811  return Member();
2812  if (members.size() == 1)
2813  return members[0];
2814  for (int i = 0; i < members.size(); ++i)
2815  if (members[i].offset() == srcMember.offset())
2816  return members[i];
2817  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2818  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2819  for (int i = 0; i < members.size(); ++i) {
2820  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2821  if (dstSeqNr == srcSeqNr)
2822  return members[i];
2823  }
2824  return Member(); // give up!
2825  }
2826 
2827  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2828  assert(dstMember && srcMember);
2829  assert(dstMember.type() == srcMember.type());
2830  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2831  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2832  syncObject(dstObj, srcObj);
2833  }
2834 
2835  // *************** Exception ***************
2836  // *
2837 
2838  Exception::Exception() {
2839  }
2840 
2841  Exception::Exception(String format, ...) {
2842  va_list arg;
2843  va_start(arg, format);
2844  Message = assemble(format, arg);
2845  va_end(arg);
2846  }
2847 
2848  Exception::Exception(String format, va_list arg) {
2849  Message = assemble(format, arg);
2850  }
2851 
2858  std::cout << "Serialization::Exception: " << Message << std::endl;
2859  }
2860 
2861  String Exception::assemble(String format, va_list arg) {
2862  char* buf = NULL;
2863  vasprintf(&buf, format.c_str(), arg);
2864  String s = buf;
2865  free(buf);
2866  return s;
2867  }
2868 
2869 } // 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.
Object & objectByBaseUID(const UID &uid)
Find true object for a base pointer.
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...