libgig  4.5.2.svn3
Serialization.cpp
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2026 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 #include "SrxFormat.h"
41 
42 #define LIBGIG_EPOCH_TIME ((time_t)0)
43 
44 namespace Serialization {
45 
46  // *************** UID ***************
47  // *
48 
49  static UID _createNullUID() {
50  const UID uid = { NULL, 0 };
51  return uid;
52  }
53 
54  const UID NO_UID = _createNullUID();
55 
67  bool UID::isValid() const {
68  return id != NULL && id != (void*)-1 && size;
69  }
70 
71  // *************** DataType ***************
72  // *
73 
85  std::map<String,DataType::NativeType> DataType::m_nativeTypes;
86 
97  m_size = 0;
98  m_isPointer = false;
99  }
100 
128  DataType::DataType(bool isPointer, int size, String baseType,
129  String customType1, String customType2)
130  {
131  m_size = size;
132  m_isPointer = isPointer;
133  m_baseTypeName = baseType;
134  m_customTypeName = customType1;
135  m_customTypeName2 = customType2;
136  }
137 
148  bool DataType::isValid() const {
149  return m_size;
150  }
151 
157  bool DataType::isPointer() const {
158  return m_isPointer;
159  }
160 
186  bool DataType::isClass() const {
187  return m_baseTypeName == "class";
188  }
189 
210  bool DataType::isPrimitive() const {
211  return !isClass() && !isArray() && !isSet() && !isMap();
212  }
213 
224  bool DataType::isString() const {
225  return m_baseTypeName == "String";
226  }
227 
242  bool DataType::isInteger() const {
243  return m_baseTypeName.substr(0, 3) == "int" ||
244  m_baseTypeName.substr(0, 4) == "uint";
245  }
246 
259  bool DataType::isReal() const {
260  return m_baseTypeName.substr(0, 4) == "real";
261  }
262 
274  bool DataType::isBool() const {
275  return m_baseTypeName == "bool";
276  }
277 
289  bool DataType::isEnum() const {
290  return m_baseTypeName == "enum";
291  }
292 
305  bool DataType::isArray() const {
306  return m_baseTypeName == "Array";
307  }
308 
321  bool DataType::isSet() const {
322  return m_baseTypeName == "Set";
323  }
324 
337  bool DataType::isMap() const {
338  return m_baseTypeName == "Map";
339  }
340 
354  bool DataType::isSigned() const {
355  return m_baseTypeName.substr(0, 3) == "int" ||
356  isReal();
357  }
358 
377  bool DataType::operator==(const DataType& other) const {
378  return m_baseTypeName == other.m_baseTypeName &&
379  m_customTypeName == other.m_customTypeName &&
380  m_customTypeName2 == other.m_customTypeName2 &&
381  (m_size == other.m_size || (isClass() && other.isClass())) &&
382  m_isPointer == other.m_isPointer;
383  }
384 
398  return m_baseTypeName + "," +
399  m_customTypeName + "," +
400  m_customTypeName2 + "," +
401  ToString(isClass()) + "," +
402  ToString(m_isPointer);
403  }
404 
410  bool DataType::operator!=(const DataType& other) const {
411  return !operator==(other);
412  }
413 
425  bool DataType::operator<(const DataType& other) const {
426  return m_baseTypeName < other.m_baseTypeName ||
427  (m_baseTypeName == other.m_baseTypeName &&
428  (m_customTypeName < other.m_customTypeName ||
429  (m_customTypeName == other.m_customTypeName &&
430  (m_customTypeName2 < other.m_customTypeName2 ||
431  (m_customTypeName2 == other.m_customTypeName2 &&
432  (m_size < other.m_size ||
433  (m_size == other.m_size &&
434  m_isPointer < other.m_isPointer)))))));
435  }
436 
448  bool DataType::operator>(const DataType& other) const {
449  return !(operator==(other) || operator<(other));
450  }
451 
467  String s = m_baseTypeName;
468  if (!m_customTypeName.empty())
469  s += " " + customTypeName(true);
470  if (!m_customTypeName2.empty())
471  s += " " + customTypeName2(true);
472  if (isPointer())
473  s += " pointer";
474  return s;
475  }
476 
507  return m_baseTypeName;
508  }
509 
510  static String _demangleTypeName(const char* name) {
511 #ifdef _MSC_VER
512  const size_t MAXLENGTH = 1024;
513  char result[MAXLENGTH];
514 
515  //FIXME: calling UnDecorateSymbolName() is not thread safe!
516  //Skip the first char
517  size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
518  if (size)
519  {
520  return result;
521  }
522  return name;
523 #else
524  int status;
525  char* result =
526  abi::__cxa_demangle(name, 0, 0, &status);
527  String sResult = result;
528  free(result);
529  return (status == 0) ? sResult : name;
530 #endif
531  }
532 
569  String DataType::customTypeName(bool demangle) const {
570  if (!demangle) return m_customTypeName;
571  return _demangleTypeName(m_customTypeName.c_str());
572  }
573 
581  String DataType::customTypeName2(bool demangle) const {
582  if (!demangle) return m_customTypeName2;
583  return _demangleTypeName(m_customTypeName2.c_str());
584  }
585 
600  const String id = internalID();
601  auto itNativeType = m_nativeTypes.find(id);
602  if (itNativeType == m_nativeTypes.end()) {
603  fprintf(stderr,
604  "(De)serialization Failure: cannot create new instance of "
605  "unknown data type '%s' !\n",
606  asLongDescr().c_str());
607  assert(false && "You may need to explicitly register this data "
608  "type by either calling "
609  "DataType::registerNativeType<T>() or using class "
610  "NativeDataTypeRegistry");
611  }
612  const std::function<Object(Archive*)>& allocFn = itNativeType->second.allocFn;
613  return allocFn(archive);
614  }
615 
616  // *************** Member ***************
617  // *
618 
632  m_uid = NO_UID;
633  m_offset = 0;
634  m_parentUID = NO_UID;
635  }
636 
637  Member::Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent) {
638  m_name = name;
639  m_uid = uid;
640  m_offset = offset;
641  m_type = type;
642  m_parentUID = parent.uid();
643  }
644 
659  UID Member::uid() const {
660  return m_uid;
661  }
662 
671  return m_parentUID;
672  }
673 
695  return m_name;
696  }
697 
739  ssize_t Member::offset() const {
740  return m_offset;
741  }
742 
747  const DataType& Member::type() const {
748  return m_type;
749  }
750 
761  bool Member::isValid() const {
762  return m_uid && !m_name.empty() && m_type;
763  }
764 
773  bool Member::operator==(const Member& other) const {
774  return m_uid == other.m_uid &&
775  m_offset == other.m_offset &&
776  m_name == other.m_name &&
777  m_type == other.m_type;
778  }
779 
785  bool Member::operator!=(const Member& other) const {
786  return !operator==(other);
787  }
788 
801  bool Member::operator<(const Member& other) const {
802  return m_uid < other.m_uid ||
803  (m_uid == other.m_uid &&
804  (m_offset < other.m_offset ||
805  (m_offset == other.m_offset &&
806  (m_name < other.m_name ||
807  (m_name == other.m_name &&
808  m_type < other.m_type)))));
809  }
810 
823  bool Member::operator>(const Member& other) const {
824  return !(operator==(other) || operator<(other));
825  }
826 
827  // *************** Object ***************
828  // *
829 
842  m_parentUID = NO_UID;
843  m_version = 0;
844  m_minVersion = 0;
845  }
846 
864  Object::Object(UIDChain uidChain, DataType type, const Object& parent) {
865  m_type = type;
866  m_uid = uidChain;
867  m_parentUID = parent.uid();
868  m_version = 0;
869  m_minVersion = 0;
870  //m_data.resize(type.size());
871  }
872 
883  bool Object::isValid() const {
884  return m_type && !m_uid.empty();
885  }
886 
898  UID Object::uid(int index) const {
899  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
900  }
901 
915  return m_parentUID;
916  }
917 
918  static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
919  if (type.isPointer()) {
920  // assuming hex encoding
921  uintptr_t addr = std::stoull(s, NULL, 16);
922  *(void**)ptr = reinterpret_cast<void*>(addr);
923  } else if (type.isPrimitive()) {
924  if (type.isInteger() || type.isEnum()) {
925  if (type.isSigned()) {
926  if (type.size() == 1)
927  *(int8_t*)ptr = strTo<int8_t>(s);
928  else if (type.size() == 2)
929  *(int16_t*)ptr = strTo<int16_t>(s);
930  else if (type.size() == 4)
931  *(int32_t*)ptr = strTo<int32_t>(s);
932  else if (type.size() == 8)
933  *(int64_t*)ptr = strTo<int64_t>(s);
934  else
935  assert(false /* unknown signed int type size */);
936  } else {
937  if (type.size() == 1)
938  *(uint8_t*)ptr = strTo<uint8_t>(s);
939  else if (type.size() == 2)
940  *(uint16_t*)ptr = strTo<uint16_t>(s);
941  else if (type.size() == 4)
942  *(uint32_t*)ptr = strTo<uint32_t>(s);
943  else if (type.size() == 8)
944  *(uint64_t*)ptr = strTo<uint64_t>(s);
945  else
946  assert(false /* unknown unsigned int type size */);
947  }
948  } else if (type.isReal()) {
949  if (type.size() == sizeof(float))
950  *(float*)ptr = strTo<float>(s);
951  else if (type.size() == sizeof(double))
952  *(double*)ptr = strTo<double>(s);
953  else
954  assert(false /* unknown floating point type */);
955  } else if (type.isBool()) {
956  String lower = toLowerCase(s);
957  const bool b = lower != "0" && lower != "false" && lower != "no";
958  *(bool*)ptr = b;
959  } else if (type.isString()) {
960  *(String*)ptr = s;
961  } else {
962  assert(false /* no built-in cast from string support for this data type */);
963  }
964  }
965  }
966 
983  const ID& id = uid().id;
984  void* ptr = (void*)id;
985  _setNativeValueFromString(ptr, m_type, s.c_str());
986  }
987 
994  const UIDChain& Object::uidChain() const {
995  return m_uid;
996  }
997 
1003  const DataType& Object::type() const {
1004  return m_type;
1005  }
1006 
1029  const RawData& Object::rawData() const {
1030  return m_data;
1031  }
1032 
1044  return m_version;
1045  }
1046 
1059  return m_minVersion;
1060  }
1061 
1094  std::vector<Member>& Object::members() {
1095  return m_members;
1096  }
1097 
1104  const std::vector<Member>& Object::members() const {
1105  return m_members;
1106  }
1107 
1118  bool Object::operator==(const Object& other) const {
1119  // ignoring all other member variables here
1120  // (since UID stands for "unique" ;-) )
1121  return m_uid == other.m_uid &&
1122  m_type == other.m_type;
1123  }
1124 
1130  bool Object::operator!=(const Object& other) const {
1131  return !operator==(other);
1132  }
1133 
1146  bool Object::operator<(const Object& other) const {
1147  // ignoring all other member variables here
1148  // (since UID stands for "unique" ;-) )
1149  return m_uid < other.m_uid ||
1150  (m_uid == other.m_uid &&
1151  m_type < other.m_type);
1152  }
1153 
1166  bool Object::operator>(const Object& other) const {
1167  return !(operator==(other) || operator<(other));
1168  }
1169 
1188  bool Object::isVersionCompatibleTo(const Object& other) const {
1189  if (this->version() == other.version())
1190  return true;
1191  if (this->version() > other.version())
1192  return this->minVersion() <= other.version();
1193  else
1194  return other.minVersion() <= this->version();
1195  }
1196 
1197  void Object::setVersion(Version v) {
1198  m_version = v;
1199  }
1200 
1201  void Object::setMinVersion(Version v) {
1202  m_minVersion = v;
1203  }
1204 
1235  for (int i = 0; i < m_members.size(); ++i)
1236  if (m_members[i].name() == name)
1237  return m_members[i];
1238  return Member();
1239  }
1240 
1255  Member Object::memberByUID(const UID& uid) const {
1256  if (!uid) return Member();
1257  for (int i = 0; i < m_members.size(); ++i)
1258  if (m_members[i].uid() == uid)
1259  return m_members[i];
1260  return Member();
1261  }
1262 
1263  void Object::remove(const Member& member) {
1264  for (int i = 0; i < m_members.size(); ++i) {
1265  if (m_members[i] == member) {
1266  m_members.erase(m_members.begin() + i);
1267  return;
1268  }
1269  }
1270  }
1271 
1287  std::vector<Member> Object::membersOfType(const DataType& type) const {
1288  std::vector<Member> v;
1289  for (int i = 0; i < m_members.size(); ++i) {
1290  const Member& member = m_members[i];
1291  if (member.type() == type)
1292  v.push_back(member);
1293  }
1294  return v;
1295  }
1296 
1328  int Object::sequenceIndexOf(const Member& member) const {
1329  for (int i = 0; i < m_members.size(); ++i)
1330  if (m_members[i] == member)
1331  return i;
1332  return -1;
1333  }
1334 
1335  // *************** Archive ***************
1336  // *
1337 
1357  m_operation = OPERATION_NONE;
1358  m_root = NO_UID;
1359  m_isModified = false;
1360  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1361  }
1362 
1378  Archive::Archive(const RawData& data) {
1379  m_operation = OPERATION_NONE;
1380  m_root = NO_UID;
1381  m_isModified = false;
1382  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1383  decode(data);
1384  }
1385 
1406  Archive::Archive(const uint8_t* data, size_t size) {
1407  m_operation = OPERATION_NONE;
1408  m_root = NO_UID;
1409  m_isModified = false;
1410  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1411  decode(data, size);
1412  }
1413 
1414  Archive::~Archive() {
1415  }
1416 
1428  return m_allObjects[m_root];
1429  }
1430 
1431  String Archive::primitiveObjectValueToString(const Object& obj) {
1432  String s;
1433  const DataType& type = obj.type();
1434  const ID& id = obj.uid().id;
1435  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1436  if (!obj.m_data.empty())
1437  assert(type.size() == obj.m_data.size());
1438  if (type.isPrimitive() && !type.isPointer()) {
1439  if (type.isInteger() || type.isEnum()) {
1440  if (type.isSigned()) {
1441  if (type.size() == 1)
1442  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1443  else if (type.size() == 2)
1444  s = ToString(*(int16_t*)ptr);
1445  else if (type.size() == 4)
1446  s = ToString(*(int32_t*)ptr);
1447  else if (type.size() == 8)
1448  s = ToString(*(int64_t*)ptr);
1449  else
1450  assert(false /* unknown signed int type size */);
1451  } else {
1452  if (type.size() == 1)
1453  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1454  else if (type.size() == 2)
1455  s = ToString(*(uint16_t*)ptr);
1456  else if (type.size() == 4)
1457  s = ToString(*(uint32_t*)ptr);
1458  else if (type.size() == 8)
1459  s = ToString(*(uint64_t*)ptr);
1460  else
1461  assert(false /* unknown unsigned int type size */);
1462  }
1463  } else if (type.isReal()) {
1464  if (type.size() == sizeof(float))
1465  s = ToString(*(float*)ptr);
1466  else if (type.size() == sizeof(double))
1467  s = ToString(*(double*)ptr);
1468  else
1469  assert(false /* unknown floating point type */);
1470  } else if (type.isBool()) {
1471  s = ToString(*(bool*)ptr);
1472  } else if (type.isString()) {
1473  s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1474  } else {
1475  assert(false /* unknown primitive type */);
1476  }
1477  }
1478  return s;
1479  }
1480 
1481  template<typename T>
1482  inline T _stringToNumber(const String& s) {
1483  assert(false /* String cast to unknown primitive number type */);
1484  }
1485 
1486  template<>
1487  inline int64_t _stringToNumber(const String& s) {
1488  return strTo<int64_t>(s);
1489  }
1490 
1491  template<>
1492  inline double _stringToNumber(const String& s) {
1493  return strTo<double>(s);
1494  }
1495 
1496  template<>
1497  inline bool _stringToNumber(const String& s) {
1498  return strTo<bool>(s);
1499  }
1500 
1501  template<typename T>
1502  static T _primitiveObjectValueToNumber(const Object& obj) {
1503  T value = 0;
1504  const DataType& type = obj.type();
1505  const ID& id = obj.uid().id;
1506  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1507  if (!obj.m_data.empty())
1508  assert(type.size() == obj.m_data.size());
1509  if (type.isPrimitive() && !type.isPointer()) {
1510  if (type.isInteger() || type.isEnum()) {
1511  if (type.isSigned()) {
1512  if (type.size() == 1)
1513  value = (T)*(int8_t*)ptr;
1514  else if (type.size() == 2)
1515  value = (T)*(int16_t*)ptr;
1516  else if (type.size() == 4)
1517  value = (T)*(int32_t*)ptr;
1518  else if (type.size() == 8)
1519  value = (T)*(int64_t*)ptr;
1520  else
1521  assert(false /* unknown signed int type size */);
1522  } else {
1523  if (type.size() == 1)
1524  value = (T)*(uint8_t*)ptr;
1525  else if (type.size() == 2)
1526  value = (T)*(uint16_t*)ptr;
1527  else if (type.size() == 4)
1528  value = (T)*(uint32_t*)ptr;
1529  else if (type.size() == 8)
1530  value = (T)*(uint64_t*)ptr;
1531  else
1532  assert(false /* unknown unsigned int type size */);
1533  }
1534  } else if (type.isReal()) {
1535  if (type.size() == sizeof(float))
1536  value = (T)*(float*)ptr;
1537  else if (type.size() == sizeof(double))
1538  value = (T)*(double*)ptr;
1539  else
1540  assert(false /* unknown floating point type */);
1541  } else if (type.isBool()) {
1542  value = (T)*(bool*)ptr;
1543  } else if (type.isString()) {
1544  value = _stringToNumber<T>(
1545  obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1546  );
1547  } else {
1548  assert(false /* unknown primitive type */);
1549  }
1550  }
1551  return value;
1552  }
1553 
1554  void Archive::encode() {
1555  m_rawData.clear();
1556  m_timeModified = time(NULL);
1557  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1558  m_timeCreated = m_timeModified;
1559 
1560  m_rawData = SrxFormat::encode(*this);
1561 
1562  m_isModified = false;
1563  }
1564 
1580  void Archive::decode(const RawData& data) {
1581  m_rawData = data;
1582  m_allObjects.clear();
1583  m_isModified = false;
1584  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1585 
1586  SrxFormat::decode(*this, data);
1587  }
1588 
1609  void Archive::decode(const uint8_t* data, size_t size) {
1610  RawData rawData;
1611  rawData.resize(size);
1612  memcpy(&rawData[0], data, size);
1613  decode(rawData);
1614  }
1615 
1632  if (m_isModified) encode();
1633  return m_rawData;
1634  }
1635 
1642  return SrxFormat::name();
1643  }
1644 
1659  bool Archive::isModified() const {
1660  return m_isModified;
1661  }
1662 
1669  m_allObjects.clear();
1670  m_operation = OPERATION_NONE;
1671  m_root = NO_UID;
1672  m_rawData.clear();
1673  m_isModified = false;
1674  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1675  }
1676 
1685  return m_name;
1686  }
1687 
1698  if (m_name == name) return;
1699  m_name = name;
1700  m_isModified = true;
1701  }
1702 
1711  return m_comment;
1712  }
1713 
1723  void Archive::setComment(String comment) {
1724  if (m_comment == comment) return;
1725  m_comment = comment;
1726  m_isModified = true;
1727  }
1728 
1729  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1730  tm* pTm;
1731  switch (base) {
1732  case LOCAL_TIME:
1733  pTm = localtime(&time);
1734  break;
1735  case UTC_TIME:
1736  pTm = gmtime(&time);
1737  break;
1738  default:
1739  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1740  }
1741  if (!pTm)
1742  throw Exception("Failed assembling time stamp structure");
1743  return *pTm;
1744  }
1745 
1751  time_t Archive::timeStampCreated() const {
1752  return m_timeCreated;
1753  }
1754 
1761  return m_timeModified;
1762  }
1763 
1775  return _convertTimeStamp(m_timeCreated, base);
1776  }
1777 
1789  return _convertTimeStamp(m_timeModified, base);
1790  }
1791 
1809  void Archive::removeMember(Object& parent, const Member& member) {
1810  parent.remove(member);
1811  m_isModified = true;
1812  }
1813 
1829  void Archive::remove(const Object& obj) {
1830  //FIXME: Should traverse from root object and remove all members associated with this object
1831  if (!obj.uid()) return;
1832  m_allObjects.erase(obj.uid());
1833  m_isModified = true;
1834  }
1835 
1849  return m_allObjects[uid];
1850  }
1851 
1867  ObjectPool::iterator it = m_allObjects.find(uid);
1868  if (it != m_allObjects.end())
1869  return it->second;
1870 
1871  // find all objects with the same ID (i.e. memory address) AND being
1872  // larger than expected by passed base UID
1873  std::map<size_t,UID> matches;
1874  for (const auto& it : m_allObjects)
1875  if (it.first.id == uid.id && it.first.size > uid.size)
1876  matches[it.first.size] = it.first;
1877 
1878  if (matches.empty())
1879  return ObjectPool::invalidObject();
1880 
1881  // return the next larger object found
1882  return m_allObjects[matches.begin()->second];
1883  }
1884 
1894  return m_allObjects[obj.parentUID()];
1895  }
1896 
1903  return m_allObjects[member.parentUID()];
1904  }
1905 
1917  if (!object) return;
1918  object.setVersion(v);
1919  m_isModified = true;
1920  }
1921 
1933  if (!object) return;
1934  object.setMinVersion(v);
1935  m_isModified = true;
1936  }
1937 
1946  void Archive::setEnumValue(Object& object, uint64_t value) {
1947  if (!object) return;
1948  if (!object.type().isEnum())
1949  throw Exception("Not an enum data type");
1950  Object* pObject = &object;
1951  if (object.type().isPointer()) {
1952  Object& obj = objectByUID(object.uid(1));
1953  if (!obj) return;
1954  pObject = &obj;
1955  }
1956  const int nativeEnumSize = sizeof(enum operation_t);
1957  DataType& type = const_cast<DataType&>( pObject->type() );
1958  // original serializer ("sender") might have had a different word size
1959  // than this machine, adjust type object in this case
1960  if (type.size() != nativeEnumSize) {
1961  type.m_size = nativeEnumSize;
1962  }
1963  pObject->m_data.resize(type.size());
1964  void* ptr = &pObject->m_data[0];
1965  if (type.size() == 1)
1966  *(uint8_t*)ptr = (uint8_t)value;
1967  else if (type.size() == 2)
1968  *(uint16_t*)ptr = (uint16_t)value;
1969  else if (type.size() == 4)
1970  *(uint32_t*)ptr = (uint32_t)value;
1971  else if (type.size() == 8)
1972  *(uint64_t*)ptr = (uint64_t)value;
1973  else
1974  assert(false /* unknown enum type size */);
1975  m_isModified = true;
1976  }
1977 
1988  void Archive::setIntValue(Object& object, int64_t value) {
1989  if (!object) return;
1990  if (!object.type().isInteger())
1991  throw Exception("Not an integer data type");
1992  Object* pObject = &object;
1993  if (object.type().isPointer()) {
1994  Object& obj = objectByUID(object.uid(1));
1995  if (!obj) return;
1996  pObject = &obj;
1997  }
1998  const DataType& type = pObject->type();
1999  pObject->m_data.resize(type.size());
2000  void* ptr = &pObject->m_data[0];
2001  if (type.isSigned()) {
2002  if (type.size() == 1)
2003  *(int8_t*)ptr = (int8_t)value;
2004  else if (type.size() == 2)
2005  *(int16_t*)ptr = (int16_t)value;
2006  else if (type.size() == 4)
2007  *(int32_t*)ptr = (int32_t)value;
2008  else if (type.size() == 8)
2009  *(int64_t*)ptr = (int64_t)value;
2010  else
2011  assert(false /* unknown signed int type size */);
2012  } else {
2013  if (type.size() == 1)
2014  *(uint8_t*)ptr = (uint8_t)value;
2015  else if (type.size() == 2)
2016  *(uint16_t*)ptr = (uint16_t)value;
2017  else if (type.size() == 4)
2018  *(uint32_t*)ptr = (uint32_t)value;
2019  else if (type.size() == 8)
2020  *(uint64_t*)ptr = (uint64_t)value;
2021  else
2022  assert(false /* unknown unsigned int type size */);
2023  }
2024  m_isModified = true;
2025  }
2026 
2038  void Archive::setRealValue(Object& object, double value) {
2039  if (!object) return;
2040  if (!object.type().isReal())
2041  throw Exception("Not a real data type");
2042  Object* pObject = &object;
2043  if (object.type().isPointer()) {
2044  Object& obj = objectByUID(object.uid(1));
2045  if (!obj) return;
2046  pObject = &obj;
2047  }
2048  const DataType& type = pObject->type();
2049  pObject->m_data.resize(type.size());
2050  void* ptr = &pObject->m_data[0];
2051  if (type.size() == sizeof(float))
2052  *(float*)ptr = (float)value;
2053  else if (type.size() == sizeof(double))
2054  *(double*)ptr = (double)value;
2055  else
2056  assert(false /* unknown real type size */);
2057  m_isModified = true;
2058  }
2059 
2068  void Archive::setBoolValue(Object& object, bool value) {
2069  if (!object) return;
2070  if (!object.type().isBool())
2071  throw Exception("Not a bool data type");
2072  Object* pObject = &object;
2073  if (object.type().isPointer()) {
2074  Object& obj = objectByUID(object.uid(1));
2075  if (!obj) return;
2076  pObject = &obj;
2077  }
2078  const DataType& type = pObject->type();
2079  pObject->m_data.resize(type.size());
2080  bool* ptr = (bool*)&pObject->m_data[0];
2081  *ptr = value;
2082  m_isModified = true;
2083  }
2084 
2093  void Archive::setStringValue(Object& object, String value) {
2094  if (!object) return;
2095  if (!object.type().isString())
2096  throw Exception("Not a String data type");
2097  Object* pObject = &object;
2098  if (object.type().isPointer()) {
2099  Object& obj = objectByUID(object.uid(1));
2100  if (!obj) return;
2101  pObject = &obj;
2102  }
2103  pObject->m_data.resize(value.length() + 1);
2104  char* ptr = (char*) &pObject->m_data[0];
2105  strcpy(ptr, &value[0]);
2106  m_isModified = true;
2107  }
2108 
2122  void Archive::setAutoValue(Object& object, String value) {
2123  if (!object) return;
2124  const DataType& type = object.type();
2125  if (type.isInteger())
2126  setIntValue(object, strTo<int64_t>(value));
2127  else if (type.isReal())
2128  setRealValue(object, strTo<double>(value));
2129  else if (type.isBool()) {
2130  String val = toLowerCase(value);
2131  if (val == "true" || val == "yes" || val == "1")
2132  setBoolValue(object, true);
2133  else if (val == "false" || val == "no" || val == "0")
2134  setBoolValue(object, false);
2135  else
2136  setBoolValue(object, strTo<bool>(value));
2137  } else if (type.isString())
2138  setStringValue(object, value);
2139  else if (type.isEnum())
2140  setEnumValue(object, strTo<uint64_t>(value));
2141  else
2142  throw Exception("Not a primitive data type");
2143  }
2144 
2155  if (!object)
2156  throw Exception("Invalid object");
2157  if (object.type().isClass())
2158  throw Exception("Object is class type");
2159  const Object* pObject = &object;
2160  if (object.type().isPointer()) {
2161  const Object& obj = objectByUID(object.uid(1));
2162  if (!obj) return "";
2163  pObject = &obj;
2164  }
2165  return primitiveObjectValueToString(*pObject);
2166  }
2167 
2177  int64_t Archive::valueAsInt(const Object& object) {
2178  if (!object)
2179  throw Exception("Invalid object");
2180  if (!object.type().isInteger() && !object.type().isEnum())
2181  throw Exception("Object is neither an integer nor an enum");
2182  const Object* pObject = &object;
2183  if (object.type().isPointer()) {
2184  const Object& obj = objectByUID(object.uid(1));
2185  if (!obj) return 0;
2186  pObject = &obj;
2187  }
2188  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2189  }
2190 
2200  double Archive::valueAsReal(const Object& object) {
2201  if (!object)
2202  throw Exception("Invalid object");
2203  if (!object.type().isReal())
2204  throw Exception("Object is not an real type");
2205  const Object* pObject = &object;
2206  if (object.type().isPointer()) {
2207  const Object& obj = objectByUID(object.uid(1));
2208  if (!obj) return 0;
2209  pObject = &obj;
2210  }
2211  return _primitiveObjectValueToNumber<double>(*pObject);
2212  }
2213 
2222  bool Archive::valueAsBool(const Object& object) {
2223  if (!object)
2224  throw Exception("Invalid object");
2225  if (!object.type().isBool())
2226  throw Exception("Object is not a bool");
2227  const Object* pObject = &object;
2228  if (object.type().isPointer()) {
2229  const Object& obj = objectByUID(object.uid(1));
2230  if (!obj) return 0;
2231  pObject = &obj;
2232  }
2233  return _primitiveObjectValueToNumber<bool>(*pObject);
2234  }
2235 
2236  Archive::operation_t Archive::operation() const {
2237  return m_operation;
2238  }
2239 
2240  // *************** Archive::Syncer ***************
2241  // *
2242 
2243  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2244  : m_dst(dst), m_src(src)
2245  {
2246  const Object srcRootObj = src.rootObject();
2247  const Object dstRootObj = dst.rootObject();
2248  if (!srcRootObj)
2249  throw Exception("No source root object!");
2250  if (!dstRootObj)
2251  throw Exception("Expected destination root object not found!");
2252  syncObject(dstRootObj, srcRootObj);
2253  }
2254 
2255  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2256  assert(srcObj.rawData().size() == dstObj.type().size());
2257  void* pDst = (void*)dstObj.uid().id;
2258  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2259  }
2260 
2261  void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2262  assert(dstObj.type().isString());
2263  assert(dstObj.type() == srcObj.type());
2264  String* pDst = (String*)(void*)dstObj.uid().id;
2265  *pDst = (String) (const char*) &srcObj.rawData()[0];
2266  }
2267 
2268  void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2269  assert(dstObj.type().isArray());
2270  assert(dstObj.type() == srcObj.type());
2271  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2272  }
2273 
2274  void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2275  assert(dstObj.type().isSet());
2276  assert(dstObj.type() == srcObj.type());
2277  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2278  }
2279 
2280  void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2281  assert(dstObj.type().isMap());
2282  assert(dstObj.type() == srcObj.type());
2283  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2284  }
2285 
2286  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2287  assert(dstObj.type().isPointer());
2288  assert(dstObj.type() == srcObj.type());
2289  void** ppDst = (void**)dstObj.uid().id;
2290  if (!srcObj.uid(1)) { // NULL pointer on source side ...
2291  *ppDst = NULL;
2292  return;
2293  }
2294  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2295  assert(pointedSrcObject);
2296  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2297  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
2298  assert(uidRelation != m_counterparts.end());
2299  const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2300  assert(pointedDstObject);
2301  *ppDst = (void*)pointedDstObject.uid().id;
2302  } else { // "strong" pointer to object, allocation required ...
2303  assert(pointedSrcObject.type());
2304  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2305  assert(pointedDstObject);
2306 
2307  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2308  *ppDst = (void*)pointedDstObject.uid().id;
2309  syncObject(pointedDstObject, pointedSrcObject);
2310  }
2311  }
2312 
2313  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2314  assert(dstObj && srcObj);
2315 
2316  // remember UID mapping between source and destination side
2317  //
2318  // As UIDs differ between source archive side and destination archive
2319  // side (as UIDs always translate to native data's real memory address),
2320  // remember their relationship, such that we can later on translate
2321  // objects from source archive side correctly to objects on destination
2322  // side, which is required to sync native pointers correctly for
2323  // pointing to respective correct, real memory address.
2324  const bool alreadySynced =
2325  !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2326 
2327  // Prevent syncing this object again, and thus also prevent endless
2328  // loop on data structures with cyclic relations.
2329  if (alreadySynced)
2330  return; // end of recursion
2331 
2332  if (!dstObj.isVersionCompatibleTo(srcObj))
2333  throw Exception("Version incompatible (destination version " +
2334  ToString(dstObj.version()) + " [min. version " +
2335  ToString(dstObj.minVersion()) + "], source version " +
2336  ToString(srcObj.version()) + " [min. version " +
2337  ToString(srcObj.minVersion()) + "])");
2338  if (dstObj.type() != srcObj.type())
2339  throw Exception("Incompatible data structure type (destination type " +
2340  dstObj.type().asLongDescr() + " vs. source type " +
2341  srcObj.type().asLongDescr() + ")");
2342 
2343  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2344  if (dstObj.type().isString())
2345  syncString(dstObj, srcObj);
2346  else
2347  syncPrimitive(dstObj, srcObj);
2348  return; // end of recursion
2349  }
2350 
2351  if (dstObj.type().isArray()) {
2352  syncArray(dstObj, srcObj);
2353  return;
2354  }
2355 
2356  if (dstObj.type().isSet()) {
2357  syncSet(dstObj, srcObj);
2358  return;
2359  }
2360 
2361  if (dstObj.type().isMap()) {
2362  syncMap(dstObj, srcObj);
2363  return;
2364  }
2365 
2366  if (dstObj.type().isPointer()) {
2367  syncPointer(dstObj, srcObj);
2368  return;
2369  }
2370 
2371  assert(dstObj.type().isClass());
2372  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2373  const Member& srcMember = srcObj.members()[iMember];
2374  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2375  if (!dstMember)
2376  throw Exception("Expected member missing in destination object");
2377  syncMember(dstMember, srcMember);
2378  }
2379  }
2380 
2381  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2382  Member dstMember = dstObj.memberNamed(srcMember.name());
2383  if (dstMember)
2384  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2385  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2386  if (members.size() <= 0)
2387  return Member();
2388  if (members.size() == 1)
2389  return members[0];
2390  for (int i = 0; i < members.size(); ++i)
2391  if (members[i].offset() == srcMember.offset())
2392  return members[i];
2393  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2394  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2395  for (int i = 0; i < members.size(); ++i) {
2396  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2397  if (dstSeqNr == srcSeqNr)
2398  return members[i];
2399  }
2400  return Member(); // give up!
2401  }
2402 
2403  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2404  assert(dstMember && srcMember);
2405  assert(dstMember.type() == srcMember.type());
2406  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2407  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2408  syncObject(dstObj, srcObj);
2409  }
2410 
2411  // *************** Exception ***************
2412  // *
2413 
2414  Exception::Exception() {
2415  }
2416 
2417  Exception::Exception(String format, ...) {
2418  va_list arg;
2419  va_start(arg, format);
2420  Message = assemble(format, arg);
2421  va_end(arg);
2422  }
2423 
2424  Exception::Exception(String format, va_list arg) {
2425  Message = assemble(format, arg);
2426  }
2427 
2434  std::cout << "Serialization::Exception: " << Message << std::endl;
2435  }
2436 
2437  String Exception::assemble(String format, va_list arg) {
2438  char* buf = NULL;
2439  vasprintf(&buf, format.c_str(), arg);
2440  String s = buf;
2441  free(buf);
2442  return s;
2443  }
2444 
2445 } // 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...