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