libgig  4.5.2.svn9
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 "srx/SrxFormat.h"
41 #include "srx/SrxJSONFormat.h"
42 
43 #define LIBGIG_EPOCH_TIME ((time_t)0)
44 
45 namespace Serialization {
46 
47  // *************** UID ***************
48  // *
49 
50  static UID _createNullUID() {
51  const UID uid = { NULL, 0 };
52  return uid;
53  }
54 
55  const UID NO_UID = _createNullUID();
56 
68  bool UID::isValid() const {
69  return id != NULL && id != (void*)-1 && size;
70  }
71 
72  // *************** DataType ***************
73  // *
74 
86  std::map<String,DataType::NativeType> DataType::m_nativeTypes;
87 
98  m_size = 0;
99  m_isPointer = false;
100  }
101 
129  DataType::DataType(bool isPointer, int size, String baseType,
130  String customType1, String customType2)
131  {
132  m_size = size;
133  m_isPointer = isPointer;
134  m_baseTypeName = baseType;
135  m_customTypeName = customType1;
136  m_customTypeName2 = customType2;
137  }
138 
149  bool DataType::isValid() const {
150  return m_size;
151  }
152 
158  bool DataType::isPointer() const {
159  return m_isPointer;
160  }
161 
187  bool DataType::isClass() const {
188  return m_baseTypeName == "class";
189  }
190 
211  bool DataType::isPrimitive() const {
212  return !isClass() && !isArray() && !isSet() && !isMap();
213  }
214 
225  bool DataType::isString() const {
226  return m_baseTypeName == "String";
227  }
228 
244  bool DataType::isChar() const {
245  return m_baseTypeName.substr(0, 4) == "char";
246  }
247 
267  bool DataType::isInteger() const {
268  return m_baseTypeName.substr(0, 3) == "int" ||
269  m_baseTypeName.substr(0, 4) == "uint";
270  }
271 
284  bool DataType::isReal() const {
285  return m_baseTypeName.substr(0, 4) == "real";
286  }
287 
302  bool DataType::isNumber() const {
303  return isInteger() || isReal();
304  }
305 
317  bool DataType::isBool() const {
318  return m_baseTypeName == "bool";
319  }
320 
332  bool DataType::isEnum() const {
333  return m_baseTypeName == "enum";
334  }
335 
348  bool DataType::isArray() const {
349  return m_baseTypeName == "Array";
350  }
351 
364  bool DataType::isSet() const {
365  return m_baseTypeName == "Set";
366  }
367 
380  bool DataType::isMap() const {
381  return m_baseTypeName == "Map";
382  }
383 
399  bool DataType::isSigned() const {
400  return m_baseTypeName.substr(0, 3) == "int" ||
401  isReal();
402  }
403 
422  bool DataType::operator==(const DataType& other) const {
423  return m_baseTypeName == other.m_baseTypeName &&
424  m_customTypeName == other.m_customTypeName &&
425  m_customTypeName2 == other.m_customTypeName2 &&
426  (m_size == other.m_size || (isClass() && other.isClass())) &&
427  m_isPointer == other.m_isPointer;
428  }
429 
443  return m_baseTypeName + "," +
444  m_customTypeName + "," +
445  m_customTypeName2 + "," +
446  ToString(isClass()) + "," +
447  ToString(m_isPointer);
448  }
449 
455  bool DataType::operator!=(const DataType& other) const {
456  return !operator==(other);
457  }
458 
470  bool DataType::operator<(const DataType& other) const {
471  return m_baseTypeName < other.m_baseTypeName ||
472  (m_baseTypeName == other.m_baseTypeName &&
473  (m_customTypeName < other.m_customTypeName ||
474  (m_customTypeName == other.m_customTypeName &&
475  (m_customTypeName2 < other.m_customTypeName2 ||
476  (m_customTypeName2 == other.m_customTypeName2 &&
477  (m_size < other.m_size ||
478  (m_size == other.m_size &&
479  m_isPointer < other.m_isPointer)))))));
480  }
481 
493  bool DataType::operator>(const DataType& other) const {
494  return !(operator==(other) || operator<(other));
495  }
496 
512  String s = m_baseTypeName;
513  if (!m_customTypeName.empty())
514  s += " " + customTypeName(true);
515  if (!m_customTypeName2.empty())
516  s += " " + customTypeName2(true);
517  if (isPointer())
518  s += " pointer";
519  return s;
520  }
521 
552  return m_baseTypeName;
553  }
554 
555  static String _demangleTypeName(const char* name) {
556 #ifdef _MSC_VER
557  const size_t MAXLENGTH = 1024;
558  char result[MAXLENGTH];
559 
560  //FIXME: calling UnDecorateSymbolName() is not thread safe!
561  //Skip the first char
562  size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
563  if (size)
564  {
565  return result;
566  }
567  return name;
568 #else
569  int status;
570  char* result =
571  abi::__cxa_demangle(name, 0, 0, &status);
572  String sResult = result;
573  free(result);
574  return (status == 0) ? sResult : name;
575 #endif
576  }
577 
614  String DataType::customTypeName(bool demangle) const {
615  if (!demangle) return m_customTypeName;
616  return _demangleTypeName(m_customTypeName.c_str());
617  }
618 
626  String DataType::customTypeName2(bool demangle) const {
627  if (!demangle) return m_customTypeName2;
628  return _demangleTypeName(m_customTypeName2.c_str());
629  }
630 
645  const String id = internalID();
646  auto itNativeType = m_nativeTypes.find(id);
647  if (itNativeType == m_nativeTypes.end()) {
648  fprintf(stderr,
649  "(De)serialization Failure: cannot create new instance of "
650  "unknown data type '%s' !\n",
651  asLongDescr().c_str());
652  assert(false && "You may need to explicitly register this data "
653  "type by either calling "
654  "DataType::registerNativeType<T>() or using class "
655  "NativeDataTypeRegistry");
656  }
657  const std::function<Object(Archive*)>& allocFn = itNativeType->second.allocFn;
658  return allocFn(archive);
659  }
660 
661  // *************** Member ***************
662  // *
663 
677  m_uid = NO_UID;
678  m_offset = 0;
679  m_parentUID = NO_UID;
680  }
681 
682  Member::Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent) {
683  m_name = name;
684  m_uid = uid;
685  m_offset = offset;
686  m_type = type;
687  m_parentUID = parent.uid();
688  }
689 
704  UID Member::uid() const {
705  return m_uid;
706  }
707 
716  return m_parentUID;
717  }
718 
740  return m_name;
741  }
742 
784  ssize_t Member::offset() const {
785  return m_offset;
786  }
787 
792  const DataType& Member::type() const {
793  return m_type;
794  }
795 
806  bool Member::isValid() const {
807  return m_uid && !m_name.empty() && m_type;
808  }
809 
818  bool Member::operator==(const Member& other) const {
819  return m_uid == other.m_uid &&
820  m_offset == other.m_offset &&
821  m_name == other.m_name &&
822  m_type == other.m_type;
823  }
824 
830  bool Member::operator!=(const Member& other) const {
831  return !operator==(other);
832  }
833 
846  bool Member::operator<(const Member& other) const {
847  return m_uid < other.m_uid ||
848  (m_uid == other.m_uid &&
849  (m_offset < other.m_offset ||
850  (m_offset == other.m_offset &&
851  (m_name < other.m_name ||
852  (m_name == other.m_name &&
853  m_type < other.m_type)))));
854  }
855 
868  bool Member::operator>(const Member& other) const {
869  return !(operator==(other) || operator<(other));
870  }
871 
872  // *************** Object ***************
873  // *
874 
887  m_parentUID = NO_UID;
888  m_version = 0;
889  m_minVersion = 0;
890  }
891 
909  Object::Object(UIDChain uidChain, DataType type, const Object& parent) {
910  m_type = type;
911  m_uid = uidChain;
912  m_parentUID = parent.uid();
913  m_version = 0;
914  m_minVersion = 0;
915  //m_data.resize(type.size());
916  }
917 
928  bool Object::isValid() const {
929  return m_type && !m_uid.empty();
930  }
931 
943  UID Object::uid(int index) const {
944  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
945  }
946 
960  return m_parentUID;
961  }
962 
963  static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
964  if (type.isPointer()) {
965  // assuming hex encoding
966  uintptr_t addr = std::stoull(s, NULL, 16);
967  *(void**)ptr = reinterpret_cast<void*>(addr);
968  } else if (type.isPrimitive()) {
969  if (type.isInteger() || type.isEnum()) {
970  if (type.isSigned()) {
971  if (type.size() == 1)
972  *(int8_t*)ptr = strTo<int8_t>(s);
973  else if (type.size() == 2)
974  *(int16_t*)ptr = strTo<int16_t>(s);
975  else if (type.size() == 4)
976  *(int32_t*)ptr = strTo<int32_t>(s);
977  else if (type.size() == 8)
978  *(int64_t*)ptr = strTo<int64_t>(s);
979  else
980  assert(false /* unknown signed int type size */);
981  } else {
982  if (type.size() == 1)
983  *(uint8_t*)ptr = strTo<uint8_t>(s);
984  else if (type.size() == 2)
985  *(uint16_t*)ptr = strTo<uint16_t>(s);
986  else if (type.size() == 4)
987  *(uint32_t*)ptr = strTo<uint32_t>(s);
988  else if (type.size() == 8)
989  *(uint64_t*)ptr = strTo<uint64_t>(s);
990  else
991  assert(false /* unknown unsigned int type size */);
992  }
993  } else if (type.isReal()) {
994  if (type.size() == sizeof(float))
995  *(float*)ptr = strTo<float>(s);
996  else if (type.size() == sizeof(double))
997  *(double*)ptr = strTo<double>(s);
998  else
999  assert(false /* unknown floating point type */);
1000  } else if (type.isChar()) {
1001  *(char*)ptr = s[0];
1002  } else if (type.isBool()) {
1003  String lower = toLowerCase(s);
1004  const bool b = lower != "0" && lower != "false" && lower != "no";
1005  *(bool*)ptr = b;
1006  } else if (type.isString()) {
1007  *(String*)ptr = s;
1008  } else {
1009  assert(false /* no built-in cast from string support for this data type */);
1010  }
1011  }
1012  }
1013 
1030  const ID& id = uid().id;
1031  void* ptr = (void*)id;
1032  _setNativeValueFromString(ptr, m_type, s.c_str());
1033  }
1034 
1041  const UIDChain& Object::uidChain() const {
1042  return m_uid;
1043  }
1044 
1050  const DataType& Object::type() const {
1051  return m_type;
1052  }
1053 
1076  const RawData& Object::rawData() const {
1077  return m_data;
1078  }
1079 
1091  return m_version;
1092  }
1093 
1106  return m_minVersion;
1107  }
1108 
1141  std::vector<Member>& Object::members() {
1142  return m_members;
1143  }
1144 
1151  const std::vector<Member>& Object::members() const {
1152  return m_members;
1153  }
1154 
1165  bool Object::operator==(const Object& other) const {
1166  // ignoring all other member variables here
1167  // (since UID stands for "unique" ;-) )
1168  return m_uid == other.m_uid &&
1169  m_type == other.m_type;
1170  }
1171 
1177  bool Object::operator!=(const Object& other) const {
1178  return !operator==(other);
1179  }
1180 
1193  bool Object::operator<(const Object& other) const {
1194  // ignoring all other member variables here
1195  // (since UID stands for "unique" ;-) )
1196  return m_uid < other.m_uid ||
1197  (m_uid == other.m_uid &&
1198  m_type < other.m_type);
1199  }
1200 
1213  bool Object::operator>(const Object& other) const {
1214  return !(operator==(other) || operator<(other));
1215  }
1216 
1235  bool Object::isVersionCompatibleTo(const Object& other) const {
1236  if (this->version() == other.version())
1237  return true;
1238  if (this->version() > other.version())
1239  return this->minVersion() <= other.version();
1240  else
1241  return other.minVersion() <= this->version();
1242  }
1243 
1244  void Object::setVersion(Version v) {
1245  m_version = v;
1246  }
1247 
1248  void Object::setMinVersion(Version v) {
1249  m_minVersion = v;
1250  }
1251 
1282  for (int i = 0; i < m_members.size(); ++i)
1283  if (m_members[i].name() == name)
1284  return m_members[i];
1285  return Member();
1286  }
1287 
1302  Member Object::memberByUID(const UID& uid) const {
1303  if (!uid) return Member();
1304  for (int i = 0; i < m_members.size(); ++i)
1305  if (m_members[i].uid() == uid)
1306  return m_members[i];
1307  return Member();
1308  }
1309 
1310  void Object::remove(const Member& member) {
1311  for (int i = 0; i < m_members.size(); ++i) {
1312  if (m_members[i] == member) {
1313  m_members.erase(m_members.begin() + i);
1314  return;
1315  }
1316  }
1317  }
1318 
1334  std::vector<Member> Object::membersOfType(const DataType& type) const {
1335  std::vector<Member> v;
1336  for (int i = 0; i < m_members.size(); ++i) {
1337  const Member& member = m_members[i];
1338  if (member.type() == type)
1339  v.push_back(member);
1340  }
1341  return v;
1342  }
1343 
1375  int Object::sequenceIndexOf(const Member& member) const {
1376  for (int i = 0; i < m_members.size(); ++i)
1377  if (m_members[i] == member)
1378  return i;
1379  return -1;
1380  }
1381 
1382  // *************** Archive ***************
1383  // *
1384 
1385  static Archive::format_t _autoDetectEncodingFormat(const RawData& data) {
1386  if (SrxFormat::checkMagicStart(data))
1387  return Archive::FORMAT_SRX;
1388  if (SrxJSONFormat::checkMagicStart(data))
1389  return Archive::FORMAT_SRX_JSON;
1390  return Archive::FORMAT_AUTO;
1391  }
1392 
1415  m_format = format;
1416  m_operation = OPERATION_NONE;
1417  m_root = NO_UID;
1418  m_isModified = false;
1419  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1420  }
1421 
1439  Archive::Archive(const RawData& data, format_t format) {
1440  m_format = format;
1441  m_operation = OPERATION_NONE;
1442  m_root = NO_UID;
1443  m_isModified = false;
1444  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1445  decode(data);
1446  }
1447 
1470  Archive::Archive(const uint8_t* data, size_t size, format_t format) {
1471  m_format = format;
1472  m_operation = OPERATION_NONE;
1473  m_root = NO_UID;
1474  m_isModified = false;
1475  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1476  decode(data, size);
1477  }
1478 
1479  Archive::~Archive() {
1480  }
1481 
1493  return m_allObjects[m_root];
1494  }
1495 
1496  String Archive::primitiveObjectValueToString(const Object& obj) {
1497  String s;
1498  const DataType& type = obj.type();
1499  const ID& id = obj.uid().id;
1500  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1501  if (!obj.m_data.empty())
1502  assert(type.size() == obj.m_data.size());
1503  if (type.isPrimitive() && !type.isPointer()) {
1504  if (type.isInteger() || type.isEnum()) {
1505  if (type.isSigned()) {
1506  if (type.size() == 1)
1507  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1508  else if (type.size() == 2)
1509  s = ToString(*(int16_t*)ptr);
1510  else if (type.size() == 4)
1511  s = ToString(*(int32_t*)ptr);
1512  else if (type.size() == 8)
1513  s = ToString(*(int64_t*)ptr);
1514  else
1515  assert(false /* unknown signed int type size */);
1516  } else {
1517  if (type.size() == 1)
1518  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1519  else if (type.size() == 2)
1520  s = ToString(*(uint16_t*)ptr);
1521  else if (type.size() == 4)
1522  s = ToString(*(uint32_t*)ptr);
1523  else if (type.size() == 8)
1524  s = ToString(*(uint64_t*)ptr);
1525  else
1526  assert(false /* unknown unsigned int type size */);
1527  }
1528  } else if (type.isReal()) {
1529  if (type.size() == sizeof(float))
1530  s = ToString(*(float*)ptr);
1531  else if (type.size() == sizeof(double))
1532  s = ToString(*(double*)ptr);
1533  else
1534  assert(false /* unknown floating point type */);
1535  } else if (type.isChar()) {
1536  s.resize(1);
1537  s[0] = *(char*)ptr;
1538  } else if (type.isBool()) {
1539  s = ToString(*(bool*)ptr);
1540  } else if (type.isString()) {
1541  s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1542  } else {
1543  assert(false /* unknown primitive type */);
1544  }
1545  }
1546  return s;
1547  }
1548 
1549  template<typename T>
1550  inline T _stringToNumber(const String& s) {
1551  assert(false /* String cast to unknown primitive number type */);
1552  }
1553 
1554  template<>
1555  inline int64_t _stringToNumber(const String& s) {
1556  return strTo<int64_t>(s);
1557  }
1558 
1559  template<>
1560  inline double _stringToNumber(const String& s) {
1561  return strTo<double>(s);
1562  }
1563 
1564  template<>
1565  inline bool _stringToNumber(const String& s) {
1566  return strTo<bool>(s);
1567  }
1568 
1569  template<typename T>
1570  static T _primitiveObjectValueToNumber(const Object& obj) {
1571  T value = 0;
1572  const DataType& type = obj.type();
1573  const ID& id = obj.uid().id;
1574  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1575  if (!obj.m_data.empty())
1576  assert(type.size() == obj.m_data.size());
1577  if (type.isPrimitive() && !type.isPointer()) {
1578  if (type.isInteger() || type.isEnum()) {
1579  if (type.isSigned()) {
1580  if (type.size() == 1)
1581  value = (T)*(int8_t*)ptr;
1582  else if (type.size() == 2)
1583  value = (T)*(int16_t*)ptr;
1584  else if (type.size() == 4)
1585  value = (T)*(int32_t*)ptr;
1586  else if (type.size() == 8)
1587  value = (T)*(int64_t*)ptr;
1588  else
1589  assert(false /* unknown signed int type size */);
1590  } else {
1591  if (type.size() == 1)
1592  value = (T)*(uint8_t*)ptr;
1593  else if (type.size() == 2)
1594  value = (T)*(uint16_t*)ptr;
1595  else if (type.size() == 4)
1596  value = (T)*(uint32_t*)ptr;
1597  else if (type.size() == 8)
1598  value = (T)*(uint64_t*)ptr;
1599  else
1600  assert(false /* unknown unsigned int type size */);
1601  }
1602  } else if (type.isReal()) {
1603  if (type.size() == sizeof(float))
1604  value = (T)*(float*)ptr;
1605  else if (type.size() == sizeof(double))
1606  value = (T)*(double*)ptr;
1607  else
1608  assert(false /* unknown floating point type */);
1609  } else if (type.isChar()) {
1610  value = (T)*(char*)ptr;
1611  } else if (type.isBool()) {
1612  value = (T)*(bool*)ptr;
1613  } else if (type.isString()) {
1614  value = _stringToNumber<T>(
1615  obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1616  );
1617  } else {
1618  assert(false /* unknown primitive type */);
1619  }
1620  }
1621  return value;
1622  }
1623 
1624  void Archive::encode() {
1625  encode(m_format);
1626  }
1627 
1628  void Archive::encode(format_t format) {
1629  m_rawData.clear();
1630  m_timeModified = time(NULL);
1631  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1632  m_timeCreated = m_timeModified;
1633  again:
1634  switch (format) {
1635  case FORMAT_AUTO:
1636  format = (m_format != FORMAT_AUTO) ? m_format : FORMAT_SRX;
1637  goto again;
1638  case FORMAT_SRX:
1639  m_rawData = SrxFormat::encode(*this);
1640  m_format = FORMAT_SRX;
1641  goto done;
1642  case FORMAT_SRX_JSON: {
1643  SrxJSONEncoder jsonEncoder;
1644  m_rawData = jsonEncoder.encode(*this);
1645  m_format = FORMAT_SRX_JSON;
1646  goto done;
1647  }
1648  }
1649  throw Exception("Requested encoding format unknown: %d", format);
1650  done:
1651  m_isModified = false;
1652  }
1653 
1669  void Archive::decode(const RawData& data) {
1670  decode(data, m_format);
1671  }
1672 
1690  void Archive::decode(const RawData& data, format_t format) {
1691  m_rawData = data;
1692  m_allObjects.clear();
1693  m_isModified = false;
1694  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1695  again:
1696  switch (format) {
1697  case FORMAT_AUTO:
1698  format = _autoDetectEncodingFormat(data);
1699  if (format == FORMAT_AUTO)
1700  throw Exception("Unknown encoding format");
1701  goto again;
1702  case FORMAT_SRX:
1703  SrxFormat::decode(*this, data);
1704  m_format = format;
1705  return;
1706  case FORMAT_SRX_JSON: {
1707  SrxJSONDecoder::decode(*this, data);
1708  m_format = format;
1709  return;
1710  }
1711  }
1712  throw Exception("Requested encoding format unknown: %d", format);
1713  }
1714 
1735  void Archive::decode(const uint8_t* data, size_t size) {
1736  decode(data, size, m_format);
1737  }
1738 
1761  void Archive::decode(const uint8_t* data, size_t size, format_t format) {
1762  RawData rawData;
1763  rawData.resize(size);
1764  memcpy(&rawData[0], data, size);
1765  decode(rawData, format);
1766  }
1767 
1784  if (m_isModified) encode();
1785  return m_rawData;
1786  }
1787 
1794  switch (m_format) {
1795  case FORMAT_AUTO:
1796  case FORMAT_SRX:
1797  return SrxFormat::name();
1798  case FORMAT_SRX_JSON:
1799  return SrxJSONFormat::name();
1800  }
1801  return "";
1802  }
1803 
1818  bool Archive::isModified() const {
1819  return m_isModified;
1820  }
1821 
1828  m_allObjects.clear();
1829  m_operation = OPERATION_NONE;
1830  m_root = NO_UID;
1831  m_rawData.clear();
1832  m_isModified = false;
1833  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1834  }
1835 
1844  return m_name;
1845  }
1846 
1857  if (m_name == name) return;
1858  m_name = name;
1859  m_isModified = true;
1860  }
1861 
1870  return m_comment;
1871  }
1872 
1882  void Archive::setComment(String comment) {
1883  if (m_comment == comment) return;
1884  m_comment = comment;
1885  m_isModified = true;
1886  }
1887 
1888  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1889  tm* pTm;
1890  switch (base) {
1891  case LOCAL_TIME:
1892  pTm = localtime(&time);
1893  break;
1894  case UTC_TIME:
1895  pTm = gmtime(&time);
1896  break;
1897  default:
1898  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1899  }
1900  if (!pTm)
1901  throw Exception("Failed assembling time stamp structure");
1902  return *pTm;
1903  }
1904 
1910  time_t Archive::timeStampCreated() const {
1911  return m_timeCreated;
1912  }
1913 
1920  return m_timeModified;
1921  }
1922 
1934  return _convertTimeStamp(m_timeCreated, base);
1935  }
1936 
1948  return _convertTimeStamp(m_timeModified, base);
1949  }
1950 
1968  void Archive::removeMember(Object& parent, const Member& member) {
1969  parent.remove(member);
1970  m_isModified = true;
1971  }
1972 
1988  void Archive::remove(const Object& obj) {
1989  //FIXME: Should traverse from root object and remove all members associated with this object
1990  if (!obj.uid()) return;
1991  m_allObjects.erase(obj.uid());
1992  m_isModified = true;
1993  }
1994 
2008  return m_allObjects[uid];
2009  }
2010 
2026  ObjectPool::iterator it = m_allObjects.find(uid);
2027  if (it != m_allObjects.end())
2028  return it->second;
2029 
2030  // find all objects with the same ID (i.e. memory address) AND being
2031  // larger than expected by passed base UID
2032  std::map<size_t,UID> matches;
2033  for (const auto& it : m_allObjects)
2034  if (it.first.id == uid.id && it.first.size > uid.size)
2035  matches[it.first.size] = it.first;
2036 
2037  if (matches.empty())
2038  return ObjectPool::invalidObject();
2039 
2040  // return the next larger object found
2041  return m_allObjects[matches.begin()->second];
2042  }
2043 
2053  return m_allObjects[obj.parentUID()];
2054  }
2055 
2062  return m_allObjects[member.parentUID()];
2063  }
2064 
2076  if (!object) return;
2077  object.setVersion(v);
2078  m_isModified = true;
2079  }
2080 
2092  if (!object) return;
2093  object.setMinVersion(v);
2094  m_isModified = true;
2095  }
2096 
2105  void Archive::setEnumValue(Object& object, uint64_t value) {
2106  if (!object) return;
2107  if (!object.type().isEnum())
2108  throw Exception("Not an enum data type");
2109  Object* pObject = &object;
2110  if (object.type().isPointer()) {
2111  Object& obj = objectByUID(object.uid(1));
2112  if (!obj) return;
2113  pObject = &obj;
2114  }
2115  const int nativeEnumSize = sizeof(enum operation_t);
2116  DataType& type = const_cast<DataType&>( pObject->type() );
2117  // original serializer ("sender") might have had a different word size
2118  // than this machine, adjust type object in this case
2119  if (type.size() != nativeEnumSize) {
2120  type.m_size = nativeEnumSize;
2121  }
2122  pObject->m_data.resize(type.size());
2123  void* ptr = &pObject->m_data[0];
2124  if (type.size() == 1)
2125  *(uint8_t*)ptr = (uint8_t)value;
2126  else if (type.size() == 2)
2127  *(uint16_t*)ptr = (uint16_t)value;
2128  else if (type.size() == 4)
2129  *(uint32_t*)ptr = (uint32_t)value;
2130  else if (type.size() == 8)
2131  *(uint64_t*)ptr = (uint64_t)value;
2132  else
2133  assert(false /* unknown enum type size */);
2134  m_isModified = true;
2135  }
2136 
2147  void Archive::setIntValue(Object& object, int64_t value) {
2148  if (!object) return;
2149  if (!object.type().isInteger())
2150  throw Exception("Not an integer data type");
2151  Object* pObject = &object;
2152  if (object.type().isPointer()) {
2153  Object& obj = objectByUID(object.uid(1));
2154  if (!obj) return;
2155  pObject = &obj;
2156  }
2157  const DataType& type = pObject->type();
2158  pObject->m_data.resize(type.size());
2159  void* ptr = &pObject->m_data[0];
2160  if (type.isSigned()) {
2161  if (type.size() == 1)
2162  *(int8_t*)ptr = (int8_t)value;
2163  else if (type.size() == 2)
2164  *(int16_t*)ptr = (int16_t)value;
2165  else if (type.size() == 4)
2166  *(int32_t*)ptr = (int32_t)value;
2167  else if (type.size() == 8)
2168  *(int64_t*)ptr = (int64_t)value;
2169  else
2170  assert(false /* unknown signed int type size */);
2171  } else {
2172  if (type.size() == 1)
2173  *(uint8_t*)ptr = (uint8_t)value;
2174  else if (type.size() == 2)
2175  *(uint16_t*)ptr = (uint16_t)value;
2176  else if (type.size() == 4)
2177  *(uint32_t*)ptr = (uint32_t)value;
2178  else if (type.size() == 8)
2179  *(uint64_t*)ptr = (uint64_t)value;
2180  else
2181  assert(false /* unknown unsigned int type size */);
2182  }
2183  m_isModified = true;
2184  }
2185 
2197  void Archive::setRealValue(Object& object, double value) {
2198  if (!object) return;
2199  if (!object.type().isReal())
2200  throw Exception("Not a real data type");
2201  Object* pObject = &object;
2202  if (object.type().isPointer()) {
2203  Object& obj = objectByUID(object.uid(1));
2204  if (!obj) return;
2205  pObject = &obj;
2206  }
2207  const DataType& type = pObject->type();
2208  pObject->m_data.resize(type.size());
2209  void* ptr = &pObject->m_data[0];
2210  if (type.size() == sizeof(float))
2211  *(float*)ptr = (float)value;
2212  else if (type.size() == sizeof(double))
2213  *(double*)ptr = (double)value;
2214  else
2215  assert(false /* unknown real type size */);
2216  m_isModified = true;
2217  }
2218 
2227  void Archive::setCharValue(Object& object, char value) {
2228  if (!object) return;
2229  if (!object.type().isChar())
2230  throw Exception("Not a char data type");
2231  Object* pObject = &object;
2232  if (object.type().isPointer()) {
2233  Object& obj = objectByUID(object.uid(1));
2234  if (!obj) return;
2235  pObject = &obj;
2236  }
2237  const DataType& type = pObject->type();
2238  pObject->m_data.resize(type.size());
2239  char* ptr = (char*)&pObject->m_data[0];
2240  *ptr = value;
2241  m_isModified = true;
2242  }
2243 
2252  void Archive::setBoolValue(Object& object, bool value) {
2253  if (!object) return;
2254  if (!object.type().isBool())
2255  throw Exception("Not a bool data type");
2256  Object* pObject = &object;
2257  if (object.type().isPointer()) {
2258  Object& obj = objectByUID(object.uid(1));
2259  if (!obj) return;
2260  pObject = &obj;
2261  }
2262  const DataType& type = pObject->type();
2263  pObject->m_data.resize(type.size());
2264  bool* ptr = (bool*)&pObject->m_data[0];
2265  *ptr = value;
2266  m_isModified = true;
2267  }
2268 
2277  void Archive::setStringValue(Object& object, String value) {
2278  if (!object) return;
2279  if (!object.type().isString())
2280  throw Exception("Not a String data type");
2281  Object* pObject = &object;
2282  if (object.type().isPointer()) {
2283  Object& obj = objectByUID(object.uid(1));
2284  if (!obj) return;
2285  pObject = &obj;
2286  }
2287  pObject->m_data.resize(value.length() + 1);
2288  char* ptr = (char*) &pObject->m_data[0];
2289  strcpy(ptr, &value[0]);
2290  m_isModified = true;
2291  }
2292 
2306  void Archive::setAutoValue(Object& object, String value) {
2307  if (!object) return;
2308  const DataType& type = object.type();
2309  if (type.isInteger())
2310  setIntValue(object, strTo<int64_t>(value));
2311  else if (type.isReal())
2312  setRealValue(object, strTo<double>(value));
2313  else if (type.isChar()) {
2314  if (value.empty())
2315  throw Exception("Empty string provided for char type");
2316  setCharValue(object, value[0]);
2317  } else if (type.isBool()) {
2318  String val = toLowerCase(value);
2319  if (val == "true" || val == "yes" || val == "1")
2320  setBoolValue(object, true);
2321  else if (val == "false" || val == "no" || val == "0")
2322  setBoolValue(object, false);
2323  else
2324  setBoolValue(object, strTo<bool>(value));
2325  } else if (type.isString())
2326  setStringValue(object, value);
2327  else if (type.isEnum())
2328  setEnumValue(object, strTo<uint64_t>(value));
2329  else
2330  throw Exception("Not a primitive data type");
2331  }
2332 
2343  if (!object)
2344  throw Exception("Invalid object");
2345  if (object.type().isClass())
2346  throw Exception("Object is class type");
2347  const Object* pObject = &object;
2348  if (object.type().isPointer()) {
2349  const Object& obj = objectByUID(object.uid(1));
2350  if (!obj) return "";
2351  pObject = &obj;
2352  }
2353  return primitiveObjectValueToString(*pObject);
2354  }
2355 
2365  int64_t Archive::valueAsInt(const Object& object) {
2366  if (!object)
2367  throw Exception("Invalid object");
2368  if (!object.type().isInteger() && !object.type().isEnum())
2369  throw Exception("Object is neither an integer nor an enum");
2370  const Object* pObject = &object;
2371  if (object.type().isPointer()) {
2372  const Object& obj = objectByUID(object.uid(1));
2373  if (!obj) return 0;
2374  pObject = &obj;
2375  }
2376  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2377  }
2378 
2388  double Archive::valueAsReal(const Object& object) {
2389  if (!object)
2390  throw Exception("Invalid object");
2391  if (!object.type().isReal())
2392  throw Exception("Object is not an real type");
2393  const Object* pObject = &object;
2394  if (object.type().isPointer()) {
2395  const Object& obj = objectByUID(object.uid(1));
2396  if (!obj) return 0;
2397  pObject = &obj;
2398  }
2399  return _primitiveObjectValueToNumber<double>(*pObject);
2400  }
2401 
2410  char Archive::valueAsChar(const Object& object) {
2411  if (!object)
2412  throw Exception("Invalid object");
2413  if (!object.type().isChar())
2414  throw Exception("Object is not a char type");
2415  const Object* pObject = &object;
2416  if (object.type().isPointer()) {
2417  const Object& obj = objectByUID(object.uid(1));
2418  if (!obj) return 0;
2419  pObject = &obj;
2420  }
2421  return _primitiveObjectValueToNumber<char>(*pObject);
2422  }
2423 
2432  bool Archive::valueAsBool(const Object& object) {
2433  if (!object)
2434  throw Exception("Invalid object");
2435  if (!object.type().isBool())
2436  throw Exception("Object is not a bool type");
2437  const Object* pObject = &object;
2438  if (object.type().isPointer()) {
2439  const Object& obj = objectByUID(object.uid(1));
2440  if (!obj) return 0;
2441  pObject = &obj;
2442  }
2443  return _primitiveObjectValueToNumber<bool>(*pObject);
2444  }
2445 
2446  Archive::operation_t Archive::operation() const {
2447  return m_operation;
2448  }
2449 
2450  // *************** Archive::Syncer ***************
2451  // *
2452 
2453  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2454  : m_dst(dst), m_src(src)
2455  {
2456  const Object srcRootObj = src.rootObject();
2457  const Object dstRootObj = dst.rootObject();
2458  if (!srcRootObj)
2459  throw Exception("No source root object!");
2460  if (!dstRootObj)
2461  throw Exception("Expected destination root object not found!");
2462  syncObject(dstRootObj, srcRootObj);
2463  }
2464 
2465  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2466  assert(srcObj.rawData().size() == dstObj.type().size());
2467  void* pDst = (void*)dstObj.uid().id;
2468  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2469  }
2470 
2471  void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2472  assert(dstObj.type().isString());
2473  assert(dstObj.type() == srcObj.type());
2474  String* pDst = (String*)(void*)dstObj.uid().id;
2475  *pDst = (String) (const char*) &srcObj.rawData()[0];
2476  }
2477 
2478  void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2479  assert(dstObj.type().isArray());
2480  assert(dstObj.type() == srcObj.type());
2481  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2482  }
2483 
2484  void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2485  assert(dstObj.type().isSet());
2486  assert(dstObj.type() == srcObj.type());
2487  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2488  }
2489 
2490  void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2491  assert(dstObj.type().isMap());
2492  assert(dstObj.type() == srcObj.type());
2493  dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2494  }
2495 
2496  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2497  assert(dstObj.type().isPointer());
2498  assert(dstObj.type() == srcObj.type());
2499  void** ppDst = (void**)dstObj.uid().id;
2500  if (!srcObj.uid(1)) { // NULL pointer on source side ...
2501  *ppDst = NULL;
2502  return;
2503  }
2504  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2505  assert(pointedSrcObject);
2506  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2507  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
2508  assert(uidRelation != m_counterparts.end());
2509  const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2510  assert(pointedDstObject);
2511  *ppDst = (void*)pointedDstObject.uid().id;
2512  } else { // "strong" pointer to object, allocation required ...
2513  assert(pointedSrcObject.type());
2514  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2515  assert(pointedDstObject);
2516 
2517  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2518  *ppDst = (void*)pointedDstObject.uid().id;
2519  syncObject(pointedDstObject, pointedSrcObject);
2520  }
2521  }
2522 
2523  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2524  assert(dstObj && srcObj);
2525 
2526  // remember UID mapping between source and destination side
2527  //
2528  // As UIDs differ between source archive side and destination archive
2529  // side (as UIDs always translate to native data's real memory address),
2530  // remember their relationship, such that we can later on translate
2531  // objects from source archive side correctly to objects on destination
2532  // side, which is required to sync native pointers correctly for
2533  // pointing to respective correct, real memory address.
2534  const bool alreadySynced =
2535  !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2536 
2537  // Prevent syncing this object again, and thus also prevent endless
2538  // loop on data structures with cyclic relations.
2539  if (alreadySynced)
2540  return; // end of recursion
2541 
2542  if (!dstObj.isVersionCompatibleTo(srcObj))
2543  throw Exception("Version incompatible (destination version " +
2544  ToString(dstObj.version()) + " [min. version " +
2545  ToString(dstObj.minVersion()) + "], source version " +
2546  ToString(srcObj.version()) + " [min. version " +
2547  ToString(srcObj.minVersion()) + "])");
2548  if (dstObj.type() != srcObj.type())
2549  throw Exception("Incompatible data structure type (destination type " +
2550  dstObj.type().asLongDescr() + " vs. source type " +
2551  srcObj.type().asLongDescr() + ")");
2552 
2553  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2554  if (dstObj.type().isString())
2555  syncString(dstObj, srcObj);
2556  else
2557  syncPrimitive(dstObj, srcObj);
2558  return; // end of recursion
2559  }
2560 
2561  if (dstObj.type().isArray()) {
2562  syncArray(dstObj, srcObj);
2563  return;
2564  }
2565 
2566  if (dstObj.type().isSet()) {
2567  syncSet(dstObj, srcObj);
2568  return;
2569  }
2570 
2571  if (dstObj.type().isMap()) {
2572  syncMap(dstObj, srcObj);
2573  return;
2574  }
2575 
2576  if (dstObj.type().isPointer()) {
2577  syncPointer(dstObj, srcObj);
2578  return;
2579  }
2580 
2581  assert(dstObj.type().isClass());
2582  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2583  const Member& srcMember = srcObj.members()[iMember];
2584  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2585  if (!dstMember)
2586  throw Exception("Expected member missing in destination object");
2587  syncMember(dstMember, srcMember);
2588  }
2589  }
2590 
2591  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2592  Member dstMember = dstObj.memberNamed(srcMember.name());
2593  if (dstMember)
2594  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2595  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2596  if (members.size() <= 0)
2597  return Member();
2598  if (members.size() == 1)
2599  return members[0];
2600  for (int i = 0; i < members.size(); ++i)
2601  if (members[i].offset() == srcMember.offset())
2602  return members[i];
2603  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2604  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2605  for (int i = 0; i < members.size(); ++i) {
2606  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2607  if (dstSeqNr == srcSeqNr)
2608  return members[i];
2609  }
2610  return Member(); // give up!
2611  }
2612 
2613  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2614  assert(dstMember && srcMember);
2615  assert(dstMember.type() == srcMember.type());
2616  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2617  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2618  syncObject(dstObj, srcObj);
2619  }
2620 
2621  // *************** Exception ***************
2622  // *
2623 
2624  Exception::Exception() {
2625  }
2626 
2627  Exception::Exception(String format, ...) {
2628  va_list arg;
2629  va_start(arg, format);
2630  Message = assemble(format, arg);
2631  va_end(arg);
2632  }
2633 
2634  Exception::Exception(String format, va_list arg) {
2635  Message = assemble(format, arg);
2636  }
2637 
2644  std::cout << "Serialization::Exception: " << Message << std::endl;
2645  }
2646 
2647  String Exception::assemble(String format, va_list arg) {
2648  char* buf = NULL;
2649  vasprintf(&buf, format.c_str(), arg);
2650  String s = buf;
2651  free(buf);
2652  return s;
2653  }
2654 
2655 } // 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 setCharValue(Object &object, char value)
Set new char value for given character object.
char valueAsChar(const Object &object)
Get char value of 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.
Archive(format_t format=FORMAT_AUTO)
Create an "empty" archive.
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.
format_t
Encoding format of serialized data stream.
@ FORMAT_AUTO
Automatically handle the encoding format:
@ FORMAT_SRX_JSON
Use and expect "Srx-JSON" encoding format (user-friendly to read and modify).
@ FORMAT_SRX
Use and expect "Srx" encoding format (simple, reliable, fast).
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 isNumber() const
Whether this is a numeric C/C++ data 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.
bool isChar() const
Whether this is a character C/C++ data type.
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.
C++ 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...