libgig  4.2.0
Serialization.cpp
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2019 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 <assert.h>
32 #include <string.h> // for memcpy()
33 #include <stdlib.h> // for atof()
34 #ifdef _MSC_VER
35 # include <windows.h>
36 # include <dbghelp.h>
37 #else
38 # include <cxxabi.h>
39 #endif
40 #include "helper.h"
41 
42 #define LIBGIG_EPOCH_TIME ((time_t)0)
43 
44 namespace Serialization {
45 
46  // *************** DataType ***************
47  // *
48 
49  static UID _createNullUID() {
50  const UID uid = { NULL, 0 };
51  return uid;
52  }
53 
54  const UID NO_UID = _createNullUID();
55 
67  bool UID::isValid() const {
68  return id != NULL && id != (void*)-1 && size;
69  }
70 
71  // *************** DataType ***************
72  // *
73 
84  m_size = 0;
85  m_isPointer = false;
86  }
87 
88  DataType::DataType(bool isPointer, int size, String baseType, String customType) {
89  m_size = size;
90  m_isPointer = isPointer;
91  m_baseTypeName = baseType;
92  m_customTypeName = customType;
93  }
94 
105  bool DataType::isValid() const {
106  return m_size;
107  }
108 
114  bool DataType::isPointer() const {
115  return m_isPointer;
116  }
117 
138  bool DataType::isClass() const {
139  return m_baseTypeName == "class";
140  }
141 
162  bool DataType::isPrimitive() const {
163  return !isClass();
164  }
165 
180  bool DataType::isInteger() const {
181  return m_baseTypeName.substr(0, 3) == "int" ||
182  m_baseTypeName.substr(0, 4) == "uint";
183  }
184 
197  bool DataType::isReal() const {
198  return m_baseTypeName.substr(0, 4) == "real";
199  }
200 
212  bool DataType::isBool() const {
213  return m_baseTypeName == "bool";
214  }
215 
227  bool DataType::isEnum() const {
228  return m_baseTypeName == "enum";
229  }
230 
244  bool DataType::isSigned() const {
245  return m_baseTypeName.substr(0, 3) == "int" ||
246  isReal();
247  }
248 
267  bool DataType::operator==(const DataType& other) const {
268  return m_baseTypeName == other.m_baseTypeName &&
269  m_customTypeName == other.m_customTypeName &&
270  (m_size == other.m_size || (isClass() && other.isClass())) &&
271  m_isPointer == other.m_isPointer;
272  }
273 
279  bool DataType::operator!=(const DataType& other) const {
280  return !operator==(other);
281  }
282 
294  bool DataType::operator<(const DataType& other) const {
295  return m_baseTypeName < other.m_baseTypeName ||
296  (m_baseTypeName == other.m_baseTypeName &&
297  (m_customTypeName < other.m_customTypeName ||
298  (m_customTypeName == other.m_customTypeName &&
299  (m_size < other.m_size ||
300  (m_size == other.m_size &&
301  m_isPointer < other.m_isPointer)))));
302  }
303 
315  bool DataType::operator>(const DataType& other) const {
316  return !(operator==(other) || operator<(other));
317  }
318 
333  String DataType::asLongDescr() const {
334  String s = m_baseTypeName;
335  if (!m_customTypeName.empty())
336  s += " " + customTypeName(true);
337  if (isPointer())
338  s += " pointer";
339  return s;
340  }
341 
371  String DataType::baseTypeName() const {
372  return m_baseTypeName;
373  }
374 
411  String DataType::customTypeName(bool demangle) const {
412  if (!demangle) return m_customTypeName;
413 #ifdef _MSC_VER
414  const size_t MAXLENGTH = 1024;
415  char result[MAXLENGTH];
416 
417  //FIXME: calling UnDecorateSymbolName() is not thread safe!
418  //Skip the first char
419  size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
420  if (size)
421  {
422  return result;
423  }
424  return m_customTypeName;
425 #else
426  int status;
427  char* result =
428  abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
429  String sResult = result;
430  free(result);
431  return (status == 0) ? sResult : m_customTypeName;
432 #endif
433  }
434 
435  // *************** Member ***************
436  // *
437 
451  m_uid = NO_UID;
452  m_offset = 0;
453  }
454 
455  Member::Member(String name, UID uid, size_t offset, DataType type) {
456  m_name = name;
457  m_uid = uid;
458  m_offset = offset;
459  m_type = type;
460  }
461 
476  UID Member::uid() const {
477  return m_uid;
478  }
479 
500  String Member::name() const {
501  return m_name;
502  }
503 
538  size_t Member::offset() const {
539  return m_offset;
540  }
541 
546  const DataType& Member::type() const {
547  return m_type;
548  }
549 
560  bool Member::isValid() const {
561  return m_uid && !m_name.empty() && m_type;
562  }
563 
572  bool Member::operator==(const Member& other) const {
573  return m_uid == other.m_uid &&
574  m_offset == other.m_offset &&
575  m_name == other.m_name &&
576  m_type == other.m_type;
577  }
578 
584  bool Member::operator!=(const Member& other) const {
585  return !operator==(other);
586  }
587 
600  bool Member::operator<(const Member& other) const {
601  return m_uid < other.m_uid ||
602  (m_uid == other.m_uid &&
603  (m_offset < other.m_offset ||
604  (m_offset == other.m_offset &&
605  (m_name < other.m_name ||
606  (m_name == other.m_name &&
607  m_type < other.m_type)))));
608  }
609 
622  bool Member::operator>(const Member& other) const {
623  return !(operator==(other) || operator<(other));
624  }
625 
626  // *************** Object ***************
627  // *
628 
641  m_version = 0;
642  m_minVersion = 0;
643  }
644 
662  Object::Object(UIDChain uidChain, DataType type) {
663  m_type = type;
664  m_uid = uidChain;
665  m_version = 0;
666  m_minVersion = 0;
667  //m_data.resize(type.size());
668  }
669 
680  bool Object::isValid() const {
681  return m_type && !m_uid.empty();
682  }
683 
695  UID Object::uid(int index) const {
696  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
697  }
698 
705  const UIDChain& Object::uidChain() const {
706  return m_uid;
707  }
708 
714  const DataType& Object::type() const {
715  return m_type;
716  }
717 
740  const RawData& Object::rawData() const {
741  return m_data;
742  }
743 
754  return m_version;
755  }
756 
769  return m_minVersion;
770  }
771 
804  std::vector<Member>& Object::members() {
805  return m_members;
806  }
807 
814  const std::vector<Member>& Object::members() const {
815  return m_members;
816  }
817 
828  bool Object::operator==(const Object& other) const {
829  // ignoring all other member variables here
830  // (since UID stands for "unique" ;-) )
831  return m_uid == other.m_uid &&
832  m_type == other.m_type;
833  }
834 
840  bool Object::operator!=(const Object& other) const {
841  return !operator==(other);
842  }
843 
856  bool Object::operator<(const Object& other) const {
857  // ignoring all other member variables here
858  // (since UID stands for "unique" ;-) )
859  return m_uid < other.m_uid ||
860  (m_uid == other.m_uid &&
861  m_type < other.m_type);
862  }
863 
876  bool Object::operator>(const Object& other) const {
877  return !(operator==(other) || operator<(other));
878  }
879 
898  bool Object::isVersionCompatibleTo(const Object& other) const {
899  if (this->version() == other.version())
900  return true;
901  if (this->version() > other.version())
902  return this->minVersion() <= other.version();
903  else
904  return other.minVersion() <= this->version();
905  }
906 
907  void Object::setVersion(Version v) {
908  m_version = v;
909  }
910 
911  void Object::setMinVersion(Version v) {
912  m_minVersion = v;
913  }
914 
944  Member Object::memberNamed(String name) const {
945  for (int i = 0; i < m_members.size(); ++i)
946  if (m_members[i].name() == name)
947  return m_members[i];
948  return Member();
949  }
950 
965  Member Object::memberByUID(const UID& uid) const {
966  if (!uid) return Member();
967  for (int i = 0; i < m_members.size(); ++i)
968  if (m_members[i].uid() == uid)
969  return m_members[i];
970  return Member();
971  }
972 
973  void Object::remove(const Member& member) {
974  for (int i = 0; i < m_members.size(); ++i) {
975  if (m_members[i] == member) {
976  m_members.erase(m_members.begin() + i);
977  return;
978  }
979  }
980  }
981 
997  std::vector<Member> Object::membersOfType(const DataType& type) const {
998  std::vector<Member> v;
999  for (int i = 0; i < m_members.size(); ++i) {
1000  const Member& member = m_members[i];
1001  if (member.type() == type)
1002  v.push_back(member);
1003  }
1004  return v;
1005  }
1006 
1038  int Object::sequenceIndexOf(const Member& member) const {
1039  for (int i = 0; i < m_members.size(); ++i)
1040  if (m_members[i] == member)
1041  return i;
1042  return -1;
1043  }
1044 
1045  // *************** Archive ***************
1046  // *
1047 
1067  m_operation = OPERATION_NONE;
1068  m_root = NO_UID;
1069  m_isModified = false;
1070  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1071  }
1072 
1088  Archive::Archive(const RawData& data) {
1089  m_operation = OPERATION_NONE;
1090  m_root = NO_UID;
1091  m_isModified = false;
1092  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1093  decode(m_rawData);
1094  }
1095 
1116  Archive::Archive(const uint8_t* data, size_t size) {
1117  m_operation = OPERATION_NONE;
1118  m_root = NO_UID;
1119  m_isModified = false;
1120  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1121  decode(data, size);
1122  }
1123 
1124  Archive::~Archive() {
1125  }
1126 
1138  return m_allObjects[m_root];
1139  }
1140 
1141  static String _encodeBlob(String data) {
1142  return ToString(data.length()) + ":" + data;
1143  }
1144 
1145  static String _encode(const UID& uid) {
1146  String s;
1147  s += _encodeBlob(ToString(size_t(uid.id)));
1148  s += _encodeBlob(ToString(size_t(uid.size)));
1149  return _encodeBlob(s);
1150  }
1151 
1152  static String _encode(const time_t& time) {
1153  return _encodeBlob(ToString(time));
1154  }
1155 
1156  static String _encode(const DataType& type) {
1157  String s;
1158  s += _encodeBlob(type.baseTypeName());
1159  s += _encodeBlob(type.customTypeName());
1160  s += _encodeBlob(ToString(type.size()));
1161  s += _encodeBlob(ToString(type.isPointer()));
1162  return _encodeBlob(s);
1163  }
1164 
1165  static String _encode(const UIDChain& chain) {
1166  String s;
1167  for (int i = 0; i < chain.size(); ++i)
1168  s += _encode(chain[i]);
1169  return _encodeBlob(s);
1170  }
1171 
1172  static String _encode(const Member& member) {
1173  String s;
1174  s += _encode(member.uid());
1175  s += _encodeBlob(ToString(member.offset()));
1176  s += _encodeBlob(member.name());
1177  s += _encode(member.type());
1178  return _encodeBlob(s);
1179  }
1180 
1181  static String _encode(const std::vector<Member>& members) {
1182  String s;
1183  for (int i = 0; i < members.size(); ++i)
1184  s += _encode(members[i]);
1185  return _encodeBlob(s);
1186  }
1187 
1188  static String _primitiveObjectValueToString(const Object& obj) {
1189  String s;
1190  const DataType& type = obj.type();
1191  const ID& id = obj.uid().id;
1192  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1193  if (!obj.m_data.empty())
1194  assert(type.size() == obj.m_data.size());
1195  if (type.isPrimitive() && !type.isPointer()) {
1196  if (type.isInteger() || type.isEnum()) {
1197  if (type.isSigned()) {
1198  if (type.size() == 1)
1199  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1200  else if (type.size() == 2)
1201  s = ToString(*(int16_t*)ptr);
1202  else if (type.size() == 4)
1203  s = ToString(*(int32_t*)ptr);
1204  else if (type.size() == 8)
1205  s = ToString(*(int64_t*)ptr);
1206  else
1207  assert(false /* unknown signed int type size */);
1208  } else {
1209  if (type.size() == 1)
1210  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1211  else if (type.size() == 2)
1212  s = ToString(*(uint16_t*)ptr);
1213  else if (type.size() == 4)
1214  s = ToString(*(uint32_t*)ptr);
1215  else if (type.size() == 8)
1216  s = ToString(*(uint64_t*)ptr);
1217  else
1218  assert(false /* unknown unsigned int type size */);
1219  }
1220  } else if (type.isReal()) {
1221  if (type.size() == sizeof(float))
1222  s = ToString(*(float*)ptr);
1223  else if (type.size() == sizeof(double))
1224  s = ToString(*(double*)ptr);
1225  else
1226  assert(false /* unknown floating point type */);
1227  } else if (type.isBool()) {
1228  s = ToString(*(bool*)ptr);
1229  } else {
1230  assert(false /* unknown primitive type */);
1231  }
1232 
1233  }
1234  return s;
1235  }
1236 
1237  template<typename T>
1238  static T _primitiveObjectValueToNumber(const Object& obj) {
1239  T value = 0;
1240  const DataType& type = obj.type();
1241  const ID& id = obj.uid().id;
1242  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1243  if (!obj.m_data.empty())
1244  assert(type.size() == obj.m_data.size());
1245  if (type.isPrimitive() && !type.isPointer()) {
1246  if (type.isInteger() || type.isEnum()) {
1247  if (type.isSigned()) {
1248  if (type.size() == 1)
1249  value = (T)*(int8_t*)ptr;
1250  else if (type.size() == 2)
1251  value = (T)*(int16_t*)ptr;
1252  else if (type.size() == 4)
1253  value = (T)*(int32_t*)ptr;
1254  else if (type.size() == 8)
1255  value = (T)*(int64_t*)ptr;
1256  else
1257  assert(false /* unknown signed int type size */);
1258  } else {
1259  if (type.size() == 1)
1260  value = (T)*(uint8_t*)ptr;
1261  else if (type.size() == 2)
1262  value = (T)*(uint16_t*)ptr;
1263  else if (type.size() == 4)
1264  value = (T)*(uint32_t*)ptr;
1265  else if (type.size() == 8)
1266  value = (T)*(uint64_t*)ptr;
1267  else
1268  assert(false /* unknown unsigned int type size */);
1269  }
1270  } else if (type.isReal()) {
1271  if (type.size() == sizeof(float))
1272  value = (T)*(float*)ptr;
1273  else if (type.size() == sizeof(double))
1274  value = (T)*(double*)ptr;
1275  else
1276  assert(false /* unknown floating point type */);
1277  } else if (type.isBool()) {
1278  value = (T)*(bool*)ptr;
1279  } else {
1280  assert(false /* unknown primitive type */);
1281  }
1282  }
1283  return value;
1284  }
1285 
1286  static String _encodePrimitiveValue(const Object& obj) {
1287  return _encodeBlob( _primitiveObjectValueToString(obj) );
1288  }
1289 
1290  static String _encode(const Object& obj) {
1291  String s;
1292  s += _encode(obj.type());
1293  s += _encodeBlob(ToString(obj.version()));
1294  s += _encodeBlob(ToString(obj.minVersion()));
1295  s += _encode(obj.uidChain());
1296  s += _encode(obj.members());
1297  s += _encodePrimitiveValue(obj);
1298  return _encodeBlob(s);
1299  }
1300 
1301  String _encode(const Archive::ObjectPool& objects) {
1302  String s;
1303  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1304  itObject != objects.end(); ++itObject)
1305  {
1306  const Object& obj = itObject->second;
1307  s += _encode(obj);
1308  }
1309  return _encodeBlob(s);
1310  }
1311 
1312  #define MAGIC_START "Srx1v"
1313  #define ENCODING_FORMAT_MINOR_VERSION 0
1314 
1315  String Archive::_encodeRootBlob() {
1316  String s;
1317  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1318  s += _encode(m_root);
1319  s += _encode(m_allObjects);
1320  s += _encodeBlob(m_name);
1321  s += _encodeBlob(m_comment);
1322  s += _encode(m_timeCreated);
1323  s += _encode(m_timeModified);
1324  return _encodeBlob(s);
1325  }
1326 
1327  void Archive::encode() {
1328  m_rawData.clear();
1329  String s = MAGIC_START;
1330  m_timeModified = time(NULL);
1331  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1332  m_timeCreated = m_timeModified;
1333  s += _encodeRootBlob();
1334  m_rawData.resize(s.length() + 1);
1335  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1336  m_isModified = false;
1337  }
1338 
1339  struct _Blob {
1340  const char* p;
1341  const char* end;
1342  };
1343 
1344  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1345  if (!bThrow && p >= end) {
1346  const _Blob blob = { p, end };
1347  return blob;
1348  }
1349  size_t sz = 0;
1350  for (; true; ++p) {
1351  if (p >= end)
1352  throw Exception("Decode Error: Missing blob");
1353  const char& c = *p;
1354  if (c == ':') break;
1355  if (c < '0' || c > '9')
1356  throw Exception("Decode Error: Missing blob size");
1357  sz *= 10;
1358  sz += size_t(c - '0');
1359  }
1360  ++p;
1361  if (p + sz > end)
1362  throw Exception("Decode Error: Premature end of blob");
1363  const _Blob blob = { p, p + sz };
1364  return blob;
1365  }
1366 
1367  template<typename T_int>
1368  static T_int _popIntBlob(const char*& p, const char* end) {
1369  _Blob blob = _decodeBlob(p, end);
1370  p = blob.p;
1371  end = blob.end;
1372 
1373  T_int sign = 1;
1374  T_int i = 0;
1375  if (p >= end)
1376  throw Exception("Decode Error: premature end of int blob");
1377  if (*p == '-') {
1378  sign = -1;
1379  ++p;
1380  }
1381  for (; p < end; ++p) {
1382  const char& c = *p;
1383  if (c < '0' || c > '9')
1384  throw Exception("Decode Error: Invalid int blob format");
1385  i *= 10;
1386  i += size_t(c - '0');
1387  }
1388  return i * sign;
1389  }
1390 
1391  template<typename T_int>
1392  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1393  const T_int i = _popIntBlob<T_int>(p, end);
1394  *(T_int*)&rawData[0] = i;
1395  }
1396 
1397  template<typename T_real>
1398  static T_real _popRealBlob(const char*& p, const char* end) {
1399  _Blob blob = _decodeBlob(p, end);
1400  p = blob.p;
1401  end = blob.end;
1402 
1403  if (p >= end || (end - p) < 1)
1404  throw Exception("Decode Error: premature end of real blob");
1405 
1406  String s(p, size_t(end - p));
1407 
1408  T_real r;
1409  if (sizeof(T_real) <= sizeof(double))
1410  r = atof(s.c_str());
1411  else
1412  assert(false /* unknown real type */);
1413 
1414  p += s.length();
1415 
1416  return r;
1417  }
1418 
1419  template<typename T_real>
1420  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1421  const T_real r = _popRealBlob<T_real>(p, end);
1422  *(T_real*)&rawData[0] = r;
1423  }
1424 
1425  static String _popStringBlob(const char*& p, const char* end) {
1426  _Blob blob = _decodeBlob(p, end);
1427  p = blob.p;
1428  end = blob.end;
1429  if (end - p < 0)
1430  throw Exception("Decode Error: missing String blob");
1431  String s;
1432  const size_t sz = end - p;
1433  s.resize(sz);
1434  memcpy(&s[0], p, sz);
1435  p += sz;
1436  return s;
1437  }
1438 
1439  static time_t _popTimeBlob(const char*& p, const char* end) {
1440  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1441  return (time_t) i;
1442  }
1443 
1444  static DataType _popDataTypeBlob(const char*& p, const char* end) {
1445  _Blob blob = _decodeBlob(p, end);
1446  p = blob.p;
1447  end = blob.end;
1448 
1449  DataType type;
1450  type.m_baseTypeName = _popStringBlob(p, end);
1451  type.m_customTypeName = _popStringBlob(p, end);
1452  type.m_size = _popIntBlob<int>(p, end);
1453  type.m_isPointer = _popIntBlob<bool>(p, end);
1454  return type;
1455  }
1456 
1457  static UID _popUIDBlob(const char*& p, const char* end) {
1458  _Blob blob = _decodeBlob(p, end);
1459  p = blob.p;
1460  end = blob.end;
1461 
1462  if (p >= end)
1463  throw Exception("Decode Error: premature end of UID blob");
1464 
1465  const ID id = (ID) _popIntBlob<size_t>(p, end);
1466  const size_t size = _popIntBlob<size_t>(p, end);
1467 
1468  const UID uid = { id, size };
1469  return uid;
1470  }
1471 
1472  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1473  _Blob blob = _decodeBlob(p, end);
1474  p = blob.p;
1475  end = blob.end;
1476 
1477  UIDChain chain;
1478  while (p < end) {
1479  const UID uid = _popUIDBlob(p, end);
1480  chain.push_back(uid);
1481  }
1482  assert(!chain.empty());
1483  return chain;
1484  }
1485 
1486  static Member _popMemberBlob(const char*& p, const char* end) {
1487  _Blob blob = _decodeBlob(p, end, false);
1488  p = blob.p;
1489  end = blob.end;
1490 
1491  Member m;
1492  if (p >= end) return m;
1493 
1494  m.m_uid = _popUIDBlob(p, end);
1495  m.m_offset = _popIntBlob<size_t>(p, end);
1496  m.m_name = _popStringBlob(p, end);
1497  m.m_type = _popDataTypeBlob(p, end);
1498  assert(m.type());
1499  assert(!m.name().empty());
1500  assert(m.uid().isValid());
1501  return m;
1502  }
1503 
1504  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1505  _Blob blob = _decodeBlob(p, end, false);
1506  p = blob.p;
1507  end = blob.end;
1508 
1509  std::vector<Member> members;
1510  while (p < end) {
1511  const Member member = _popMemberBlob(p, end);
1512  if (member)
1513  members.push_back(member);
1514  else
1515  break;
1516  }
1517  return members;
1518  }
1519 
1520  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1521  const DataType& type = obj.type();
1522  if (type.isPrimitive() && !type.isPointer()) {
1523  obj.m_data.resize(type.size());
1524  if (type.isInteger() || type.isEnum()) {
1525  if (type.isSigned()) {
1526  if (type.size() == 1)
1527  _popIntBlob<int8_t>(p, end, obj.m_data);
1528  else if (type.size() == 2)
1529  _popIntBlob<int16_t>(p, end, obj.m_data);
1530  else if (type.size() == 4)
1531  _popIntBlob<int32_t>(p, end, obj.m_data);
1532  else if (type.size() == 8)
1533  _popIntBlob<int64_t>(p, end, obj.m_data);
1534  else
1535  assert(false /* unknown signed int type size */);
1536  } else {
1537  if (type.size() == 1)
1538  _popIntBlob<uint8_t>(p, end, obj.m_data);
1539  else if (type.size() == 2)
1540  _popIntBlob<uint16_t>(p, end, obj.m_data);
1541  else if (type.size() == 4)
1542  _popIntBlob<uint32_t>(p, end, obj.m_data);
1543  else if (type.size() == 8)
1544  _popIntBlob<uint64_t>(p, end, obj.m_data);
1545  else
1546  assert(false /* unknown unsigned int type size */);
1547  }
1548  } else if (type.isReal()) {
1549  if (type.size() == sizeof(float))
1550  _popRealBlob<float>(p, end, obj.m_data);
1551  else if (type.size() == sizeof(double))
1552  _popRealBlob<double>(p, end, obj.m_data);
1553  else
1554  assert(false /* unknown floating point type */);
1555  } else if (type.isBool()) {
1556  _popIntBlob<uint8_t>(p, end, obj.m_data);
1557  } else {
1558  assert(false /* unknown primitive type */);
1559  }
1560 
1561  } else {
1562  // don't whine if the empty blob was not added on encoder side
1563  _Blob blob = _decodeBlob(p, end, false);
1564  p = blob.p;
1565  end = blob.end;
1566  }
1567  }
1568 
1569  static Object _popObjectBlob(const char*& p, const char* end) {
1570  _Blob blob = _decodeBlob(p, end, false);
1571  p = blob.p;
1572  end = blob.end;
1573 
1574  Object obj;
1575  if (p >= end) return obj;
1576 
1577  obj.m_type = _popDataTypeBlob(p, end);
1578  obj.m_version = _popIntBlob<Version>(p, end);
1579  obj.m_minVersion = _popIntBlob<Version>(p, end);
1580  obj.m_uid = _popUIDChainBlob(p, end);
1581  obj.m_members = _popMembersBlob(p, end);
1582  _popPrimitiveValue(p, end, obj);
1583  assert(obj.type());
1584  return obj;
1585  }
1586 
1587  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1588  _Blob blob = _decodeBlob(p, end, false);
1589  p = blob.p;
1590  end = blob.end;
1591 
1592  if (p >= end)
1593  throw Exception("Decode Error: Premature end of objects blob");
1594 
1595  while (true) {
1596  const Object obj = _popObjectBlob(p, end);
1597  if (!obj) break;
1598  m_allObjects[obj.uid()] = obj;
1599  }
1600  }
1601 
1602  void Archive::_popRootBlob(const char*& p, const char* end) {
1603  _Blob blob = _decodeBlob(p, end, false);
1604  p = blob.p;
1605  end = blob.end;
1606 
1607  if (p >= end)
1608  throw Exception("Decode Error: Premature end of root blob");
1609 
1610  // just in case this encoding format will be extended in future
1611  // (currently not used)
1612  const int formatMinorVersion = _popIntBlob<int>(p, end);
1613 
1614  m_root = _popUIDBlob(p, end);
1615  if (!m_root)
1616  throw Exception("Decode Error: No root object");
1617 
1618  _popObjectsBlob(p, end);
1619  if (!m_allObjects[m_root])
1620  throw Exception("Decode Error: Missing declared root object");
1621 
1622  m_name = _popStringBlob(p, end);
1623  m_comment = _popStringBlob(p, end);
1624  m_timeCreated = _popTimeBlob(p, end);
1625  m_timeModified = _popTimeBlob(p, end);
1626  }
1627 
1643  void Archive::decode(const RawData& data) {
1644  m_rawData = data;
1645  m_allObjects.clear();
1646  m_isModified = false;
1647  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1648  const char* p = (const char*) &data[0];
1649  const char* end = p + data.size();
1650  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1651  throw Exception("Decode Error: Magic start missing!");
1652  p += strlen(MAGIC_START);
1653  _popRootBlob(p, end);
1654  }
1655 
1676  void Archive::decode(const uint8_t* data, size_t size) {
1677  RawData rawData;
1678  rawData.resize(size);
1679  memcpy(&rawData[0], data, size);
1680  decode(rawData);
1681  }
1682 
1699  if (m_isModified) encode();
1700  return m_rawData;
1701  }
1702 
1708  String Archive::rawDataFormat() const {
1709  return MAGIC_START;
1710  }
1711 
1726  bool Archive::isModified() const {
1727  return m_isModified;
1728  }
1729 
1736  m_allObjects.clear();
1737  m_operation = OPERATION_NONE;
1738  m_root = NO_UID;
1739  m_rawData.clear();
1740  m_isModified = false;
1741  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1742  }
1743 
1751  String Archive::name() const {
1752  return m_name;
1753  }
1754 
1764  void Archive::setName(String name) {
1765  if (m_name == name) return;
1766  m_name = name;
1767  m_isModified = true;
1768  }
1769 
1777  String Archive::comment() const {
1778  return m_comment;
1779  }
1780 
1790  void Archive::setComment(String comment) {
1791  if (m_comment == comment) return;
1792  m_comment = comment;
1793  m_isModified = true;
1794  }
1795 
1796  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1797  tm* pTm;
1798  switch (base) {
1799  case LOCAL_TIME:
1800  pTm = localtime(&time);
1801  break;
1802  case UTC_TIME:
1803  pTm = gmtime(&time);
1804  break;
1805  default:
1806  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1807  }
1808  if (!pTm)
1809  throw Exception("Failed assembling time stamp structure");
1810  return *pTm;
1811  }
1812 
1818  time_t Archive::timeStampCreated() const {
1819  return m_timeCreated;
1820  }
1821 
1828  return m_timeModified;
1829  }
1830 
1842  return _convertTimeStamp(m_timeCreated, base);
1843  }
1844 
1856  return _convertTimeStamp(m_timeModified, base);
1857  }
1858 
1876  void Archive::removeMember(Object& parent, const Member& member) {
1877  parent.remove(member);
1878  m_isModified = true;
1879  }
1880 
1896  void Archive::remove(const Object& obj) {
1897  //FIXME: Should traverse from root object and remove all members associated with this object
1898  if (!obj.uid()) return;
1899  m_allObjects.erase(obj.uid());
1900  m_isModified = true;
1901  }
1902 
1915  return m_allObjects[uid];
1916  }
1917 
1929  if (!object) return;
1930  object.setVersion(v);
1931  m_isModified = true;
1932  }
1933 
1945  if (!object) return;
1946  object.setMinVersion(v);
1947  m_isModified = true;
1948  }
1949 
1958  void Archive::setEnumValue(Object& object, uint64_t value) {
1959  if (!object) return;
1960  if (!object.type().isEnum())
1961  throw Exception("Not an enum data type");
1962  Object* pObject = &object;
1963  if (object.type().isPointer()) {
1964  Object& obj = objectByUID(object.uid(1));
1965  if (!obj) return;
1966  pObject = &obj;
1967  }
1968  const int nativeEnumSize = sizeof(enum operation_t);
1969  DataType& type = const_cast<DataType&>( pObject->type() );
1970  // original serializer ("sender") might have had a different word size
1971  // than this machine, adjust type object in this case
1972  if (type.size() != nativeEnumSize) {
1973  type.m_size = nativeEnumSize;
1974  }
1975  pObject->m_data.resize(type.size());
1976  void* ptr = &pObject->m_data[0];
1977  if (type.size() == 1)
1978  *(uint8_t*)ptr = (uint8_t)value;
1979  else if (type.size() == 2)
1980  *(uint16_t*)ptr = (uint16_t)value;
1981  else if (type.size() == 4)
1982  *(uint32_t*)ptr = (uint32_t)value;
1983  else if (type.size() == 8)
1984  *(uint64_t*)ptr = (uint64_t)value;
1985  else
1986  assert(false /* unknown enum type size */);
1987  m_isModified = true;
1988  }
1989 
2000  void Archive::setIntValue(Object& object, int64_t value) {
2001  if (!object) return;
2002  if (!object.type().isInteger())
2003  throw Exception("Not an integer data type");
2004  Object* pObject = &object;
2005  if (object.type().isPointer()) {
2006  Object& obj = objectByUID(object.uid(1));
2007  if (!obj) return;
2008  pObject = &obj;
2009  }
2010  const DataType& type = pObject->type();
2011  pObject->m_data.resize(type.size());
2012  void* ptr = &pObject->m_data[0];
2013  if (type.isSigned()) {
2014  if (type.size() == 1)
2015  *(int8_t*)ptr = (int8_t)value;
2016  else if (type.size() == 2)
2017  *(int16_t*)ptr = (int16_t)value;
2018  else if (type.size() == 4)
2019  *(int32_t*)ptr = (int32_t)value;
2020  else if (type.size() == 8)
2021  *(int64_t*)ptr = (int64_t)value;
2022  else
2023  assert(false /* unknown signed int type size */);
2024  } else {
2025  if (type.size() == 1)
2026  *(uint8_t*)ptr = (uint8_t)value;
2027  else if (type.size() == 2)
2028  *(uint16_t*)ptr = (uint16_t)value;
2029  else if (type.size() == 4)
2030  *(uint32_t*)ptr = (uint32_t)value;
2031  else if (type.size() == 8)
2032  *(uint64_t*)ptr = (uint64_t)value;
2033  else
2034  assert(false /* unknown unsigned int type size */);
2035  }
2036  m_isModified = true;
2037  }
2038 
2050  void Archive::setRealValue(Object& object, double value) {
2051  if (!object) return;
2052  if (!object.type().isReal())
2053  throw Exception("Not a real data type");
2054  Object* pObject = &object;
2055  if (object.type().isPointer()) {
2056  Object& obj = objectByUID(object.uid(1));
2057  if (!obj) return;
2058  pObject = &obj;
2059  }
2060  const DataType& type = pObject->type();
2061  pObject->m_data.resize(type.size());
2062  void* ptr = &pObject->m_data[0];
2063  if (type.size() == sizeof(float))
2064  *(float*)ptr = (float)value;
2065  else if (type.size() == sizeof(double))
2066  *(double*)ptr = (double)value;
2067  else
2068  assert(false /* unknown real type size */);
2069  m_isModified = true;
2070  }
2071 
2080  void Archive::setBoolValue(Object& object, bool value) {
2081  if (!object) return;
2082  if (!object.type().isBool())
2083  throw Exception("Not a bool data type");
2084  Object* pObject = &object;
2085  if (object.type().isPointer()) {
2086  Object& obj = objectByUID(object.uid(1));
2087  if (!obj) return;
2088  pObject = &obj;
2089  }
2090  const DataType& type = pObject->type();
2091  pObject->m_data.resize(type.size());
2092  bool* ptr = (bool*)&pObject->m_data[0];
2093  *ptr = value;
2094  m_isModified = true;
2095  }
2096 
2110  void Archive::setAutoValue(Object& object, String value) {
2111  if (!object) return;
2112  const DataType& type = object.type();
2113  if (type.isInteger())
2114  setIntValue(object, atoll(value.c_str()));
2115  else if (type.isReal())
2116  setRealValue(object, atof(value.c_str()));
2117  else if (type.isBool()) {
2118  String val = toLowerCase(value);
2119  if (val == "true" || val == "yes" || val == "1")
2120  setBoolValue(object, true);
2121  else if (val == "false" || val == "no" || val == "0")
2122  setBoolValue(object, false);
2123  else
2124  setBoolValue(object, atof(value.c_str()));
2125  } else if (type.isEnum())
2126  setEnumValue(object, atoll(value.c_str()));
2127  else
2128  throw Exception("Not a primitive data type");
2129  }
2130 
2140  String Archive::valueAsString(const Object& object) {
2141  if (!object)
2142  throw Exception("Invalid object");
2143  if (object.type().isClass())
2144  throw Exception("Object is class type");
2145  const Object* pObject = &object;
2146  if (object.type().isPointer()) {
2147  const Object& obj = objectByUID(object.uid(1));
2148  if (!obj) return "";
2149  pObject = &obj;
2150  }
2151  return _primitiveObjectValueToString(*pObject);
2152  }
2153 
2163  int64_t Archive::valueAsInt(const Object& object) {
2164  if (!object)
2165  throw Exception("Invalid object");
2166  if (!object.type().isInteger() && !object.type().isEnum())
2167  throw Exception("Object is neither an integer nor an enum");
2168  const Object* pObject = &object;
2169  if (object.type().isPointer()) {
2170  const Object& obj = objectByUID(object.uid(1));
2171  if (!obj) return 0;
2172  pObject = &obj;
2173  }
2174  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2175  }
2176 
2186  double Archive::valueAsReal(const Object& object) {
2187  if (!object)
2188  throw Exception("Invalid object");
2189  if (!object.type().isReal())
2190  throw Exception("Object is not an real type");
2191  const Object* pObject = &object;
2192  if (object.type().isPointer()) {
2193  const Object& obj = objectByUID(object.uid(1));
2194  if (!obj) return 0;
2195  pObject = &obj;
2196  }
2197  return _primitiveObjectValueToNumber<double>(*pObject);
2198  }
2199 
2208  bool Archive::valueAsBool(const Object& object) {
2209  if (!object)
2210  throw Exception("Invalid object");
2211  if (!object.type().isBool())
2212  throw Exception("Object is not a bool");
2213  const Object* pObject = &object;
2214  if (object.type().isPointer()) {
2215  const Object& obj = objectByUID(object.uid(1));
2216  if (!obj) return 0;
2217  pObject = &obj;
2218  }
2219  return _primitiveObjectValueToNumber<bool>(*pObject);
2220  }
2221 
2222  // *************** Archive::Syncer ***************
2223  // *
2224 
2225  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2226  : m_dst(dst), m_src(src)
2227  {
2228  const Object srcRootObj = src.rootObject();
2229  const Object dstRootObj = dst.rootObject();
2230  if (!srcRootObj)
2231  throw Exception("No source root object!");
2232  if (!dstRootObj)
2233  throw Exception("Expected destination root object not found!");
2234  syncObject(dstRootObj, srcRootObj);
2235  }
2236 
2237  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2238  assert(srcObj.rawData().size() == dstObj.type().size());
2239  void* pDst = (void*)dstObj.uid().id;
2240  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2241  }
2242 
2243  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2244  assert(dstObj.type().isPointer());
2245  assert(dstObj.type() == srcObj.type());
2246  const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2247  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2248  syncObject(pointedDstObject, pointedSrcObject);
2249  }
2250 
2251  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2252  if (!dstObj || !srcObj) return; // end of recursion
2253  if (!dstObj.isVersionCompatibleTo(srcObj))
2254  throw Exception("Version incompatible (destination version " +
2255  ToString(dstObj.version()) + " [min. version " +
2256  ToString(dstObj.minVersion()) + "], source version " +
2257  ToString(srcObj.version()) + " [min. version " +
2258  ToString(srcObj.minVersion()) + "])");
2259  if (dstObj.type() != srcObj.type())
2260  throw Exception("Incompatible data structure type (destination type " +
2261  dstObj.type().asLongDescr() + " vs. source type " +
2262  srcObj.type().asLongDescr() + ")");
2263 
2264  // prevent syncing this object again, and thus also prevent endless
2265  // loop on data structures with cyclic relations
2266  m_dst.m_allObjects.erase(dstObj.uid());
2267 
2268  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2269  syncPrimitive(dstObj, srcObj);
2270  return; // end of recursion
2271  }
2272 
2273  if (dstObj.type().isPointer()) {
2274  syncPointer(dstObj, srcObj);
2275  return;
2276  }
2277 
2278  assert(dstObj.type().isClass());
2279  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2280  const Member& srcMember = srcObj.members()[iMember];
2281  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2282  if (!dstMember)
2283  throw Exception("Expected member missing in destination object");
2284  syncMember(dstMember, srcMember);
2285  }
2286  }
2287 
2288  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2289  Member dstMember = dstObj.memberNamed(srcMember.name());
2290  if (dstMember)
2291  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2292  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2293  if (members.size() <= 0)
2294  return Member();
2295  if (members.size() == 1)
2296  return members[0];
2297  for (int i = 0; i < members.size(); ++i)
2298  if (members[i].offset() == srcMember.offset())
2299  return members[i];
2300  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2301  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2302  for (int i = 0; i < members.size(); ++i) {
2303  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2304  if (dstSeqNr == srcSeqNr)
2305  return members[i];
2306  }
2307  return Member(); // give up!
2308  }
2309 
2310  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2311  assert(dstMember && srcMember);
2312  assert(dstMember.type() == srcMember.type());
2313  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2314  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2315  syncObject(dstObj, srcObj);
2316  }
2317 
2318  // *************** Exception ***************
2319  // *
2320 
2321  Exception::Exception() {
2322  }
2323 
2324  Exception::Exception(String format, ...) {
2325  va_list arg;
2326  va_start(arg, format);
2327  Message = assemble(format, arg);
2328  va_end(arg);
2329  }
2330 
2331  Exception::Exception(String format, va_list arg) {
2332  Message = assemble(format, arg);
2333  }
2334 
2341  std::cout << "Serialization::Exception: " << Message << std::endl;
2342  }
2343 
2344  String Exception::assemble(String format, va_list arg) {
2345  char* buf = NULL;
2346  vasprintf(&buf, format.c_str(), arg);
2347  String s = buf;
2348  free(buf);
2349  return s;
2350  }
2351 
2352 } // namespace Serialization
String customTypeName(bool demangle=false) const
The 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.
String baseTypeName() const
The base type name of this data type.
Abstract reflection of some native serialized C/C++ data.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
void setName(String name)
Assign a name to this archive.
Destination container for serialization, and source container for deserialization.
std::vector< UID > UIDChain
Chain of UIDs.
bool operator==(const Member &other) const
Comparison for equalness.
void clear()
Clear content of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
void * ID
Abstract identifier for serialized C++ objects.
String name() const
Optional name of this archive.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
int64_t valueAsInt(const Object &object)
Get integer value of object.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
Abstract reflection of a native C++ data type.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
const RawData & rawData()
Raw data stream of this archive content.
time_t timeStampCreated() const
Date and time when this archive was initially created.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
uint32_t Version
Version number data type.
bool operator<(const DataType &other) const
Smaller than comparison.
bool isValid() const
Check if this is a valid DataType object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
time_base_t
To which time zone a certain timing information relates to.
bool operator==(const Object &other) const
Comparison for equalness.
bool isValid() const
Check whether this is a valid unique identifier.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
Unique identifier referring to one specific native C++ object, member, fundamental variable...
bool isValid() const
Check if this is a valid Object instance.
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 isBool() const
Whether this is a boolean C/C++ data type.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
Object & rootObject()
Root C++ object of this archive.
ID id
Abstract non-unique ID of the object or member in question.
String comment() const
Optional comments for this archive.
bool operator<(const Object &other) const
Smaller than comparison.
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
The time stamp relates to the machine&#39;s local time zone. Request a time stamp in local time if you wa...
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"...
Will be thrown whenever an error occurs during an serialization or deserialization process...
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
String valueAsString(const Object &object)
Get value of object as string.
Version version() const
Version of original user defined C/C++ struct or class.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
const DataType & type() const
C/C++ Data type of this member.
bool operator>(const DataType &other) const
Greater than comparison.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool isEnum() const
Whether this is a C/C++ enum data type.
Archive()
Create an "empty" archive.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
Object()
Default constructor (for an "invalid" Object).
bool isReal() const
Whether this is a floating point based C/C++ data type.
UID uid() const
Unique identifier of this member instance.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
Member memberNamed(String name) const
Get the member of this Object with given name.
void PrintMessage()
Print exception message to stdout.
String asLongDescr() const
Human readable long description for this data type.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
UID uid(int index=0) const
Unique identifier of this Object.
double valueAsReal(const Object &object)
Get floating point value of object.
size_t size() const
Returns native memory size of the respective C++ object or variable.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
bool isModified() const
Whether this archive was modified.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isValid() const
Check if this is a valid Member object.
bool operator>(const Object &other) const
Greater than comparison.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
void setComment(String comment)
Assign a comment to this archive.
Serialization / deserialization framework.
Definition: gig.h:91
bool operator<(const Member &other) const
Smaller than comparison.
DataType()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
size_t size
Memory size of the object or member in question.
Abstract reflection of a native C++ class/struct&#39;s member variable.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
void remove(const Object &obj)
Remove an object from this archive.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator>(const Member &other) const
Greater than comparison.
Member()
Default constructor.
size_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.