libgig  4.1.0.svn8
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 #include <cxxabi.h>
35 
36 #include "helper.h"
37 
38 #define LIBGIG_EPOCH_TIME ((time_t)0)
39 
40 namespace Serialization {
41 
42  // *************** DataType ***************
43  // *
44 
45  static UID _createNullUID() {
46  const UID uid = { NULL, 0 };
47  return uid;
48  }
49 
50  const UID NO_UID = _createNullUID();
51 
63  bool UID::isValid() const {
64  return id != NULL && id != (void*)-1 && size;
65  }
66 
67  // *************** DataType ***************
68  // *
69 
80  m_size = 0;
81  m_isPointer = false;
82  }
83 
84  DataType::DataType(bool isPointer, int size, String baseType, String customType) {
85  m_size = size;
86  m_isPointer = isPointer;
87  m_baseTypeName = baseType;
88  m_customTypeName = customType;
89  }
90 
101  bool DataType::isValid() const {
102  return m_size;
103  }
104 
110  bool DataType::isPointer() const {
111  return m_isPointer;
112  }
113 
134  bool DataType::isClass() const {
135  return m_baseTypeName == "class";
136  }
137 
158  bool DataType::isPrimitive() const {
159  return !isClass();
160  }
161 
176  bool DataType::isInteger() const {
177  return m_baseTypeName.substr(0, 3) == "int" ||
178  m_baseTypeName.substr(0, 4) == "uint";
179  }
180 
193  bool DataType::isReal() const {
194  return m_baseTypeName.substr(0, 4) == "real";
195  }
196 
208  bool DataType::isBool() const {
209  return m_baseTypeName == "bool";
210  }
211 
223  bool DataType::isEnum() const {
224  return m_baseTypeName == "enum";
225  }
226 
240  bool DataType::isSigned() const {
241  return m_baseTypeName.substr(0, 3) == "int" ||
242  isReal();
243  }
244 
263  bool DataType::operator==(const DataType& other) const {
264  return m_baseTypeName == other.m_baseTypeName &&
265  m_customTypeName == other.m_customTypeName &&
266  (m_size == other.m_size || (isClass() && other.isClass())) &&
267  m_isPointer == other.m_isPointer;
268  }
269 
275  bool DataType::operator!=(const DataType& other) const {
276  return !operator==(other);
277  }
278 
290  bool DataType::operator<(const DataType& other) const {
291  return m_baseTypeName < other.m_baseTypeName ||
292  (m_baseTypeName == other.m_baseTypeName &&
293  (m_customTypeName < other.m_customTypeName ||
294  (m_customTypeName == other.m_customTypeName &&
295  (m_size < other.m_size ||
296  (m_size == other.m_size &&
297  m_isPointer < other.m_isPointer)))));
298  }
299 
311  bool DataType::operator>(const DataType& other) const {
312  return !(operator==(other) || operator<(other));
313  }
314 
329  String DataType::asLongDescr() const {
330  String s = m_baseTypeName;
331  if (!m_customTypeName.empty())
332  s += " " + customTypeName(true);
333  if (isPointer())
334  s += " pointer";
335  return s;
336  }
337 
367  String DataType::baseTypeName() const {
368  return m_baseTypeName;
369  }
370 
404  String DataType::customTypeName(bool demangle) const {
405  if (!demangle) return m_customTypeName;
406  int status;
407  const char* result =
408  abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
409  return (status == 0) ? result : m_customTypeName;
410  }
411 
412  // *************** Member ***************
413  // *
414 
428  m_uid = NO_UID;
429  m_offset = 0;
430  }
431 
432  Member::Member(String name, UID uid, size_t offset, DataType type) {
433  m_name = name;
434  m_uid = uid;
435  m_offset = offset;
436  m_type = type;
437  }
438 
453  UID Member::uid() const {
454  return m_uid;
455  }
456 
477  String Member::name() const {
478  return m_name;
479  }
480 
515  size_t Member::offset() const {
516  return m_offset;
517  }
518 
523  const DataType& Member::type() const {
524  return m_type;
525  }
526 
537  bool Member::isValid() const {
538  return m_uid && !m_name.empty() && m_type;
539  }
540 
549  bool Member::operator==(const Member& other) const {
550  return m_uid == other.m_uid &&
551  m_offset == other.m_offset &&
552  m_name == other.m_name &&
553  m_type == other.m_type;
554  }
555 
561  bool Member::operator!=(const Member& other) const {
562  return !operator==(other);
563  }
564 
577  bool Member::operator<(const Member& other) const {
578  return m_uid < other.m_uid ||
579  (m_uid == other.m_uid &&
580  (m_offset < other.m_offset ||
581  (m_offset == other.m_offset &&
582  (m_name < other.m_name ||
583  (m_name == other.m_name &&
584  m_type < other.m_type)))));
585  }
586 
599  bool Member::operator>(const Member& other) const {
600  return !(operator==(other) || operator<(other));
601  }
602 
603  // *************** Object ***************
604  // *
605 
618  m_version = 0;
619  m_minVersion = 0;
620  }
621 
639  Object::Object(UIDChain uidChain, DataType type) {
640  m_type = type;
641  m_uid = uidChain;
642  m_version = 0;
643  m_minVersion = 0;
644  //m_data.resize(type.size());
645  }
646 
657  bool Object::isValid() const {
658  return m_type && !m_uid.empty();
659  }
660 
672  UID Object::uid(int index) const {
673  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
674  }
675 
682  const UIDChain& Object::uidChain() const {
683  return m_uid;
684  }
685 
691  const DataType& Object::type() const {
692  return m_type;
693  }
694 
717  const RawData& Object::rawData() const {
718  return m_data;
719  }
720 
731  return m_version;
732  }
733 
746  return m_minVersion;
747  }
748 
781  std::vector<Member>& Object::members() {
782  return m_members;
783  }
784 
791  const std::vector<Member>& Object::members() const {
792  return m_members;
793  }
794 
805  bool Object::operator==(const Object& other) const {
806  // ignoring all other member variables here
807  // (since UID stands for "unique" ;-) )
808  return m_uid == other.m_uid &&
809  m_type == other.m_type;
810  }
811 
817  bool Object::operator!=(const Object& other) const {
818  return !operator==(other);
819  }
820 
833  bool Object::operator<(const Object& other) const {
834  // ignoring all other member variables here
835  // (since UID stands for "unique" ;-) )
836  return m_uid < other.m_uid ||
837  (m_uid == other.m_uid &&
838  m_type < other.m_type);
839  }
840 
853  bool Object::operator>(const Object& other) const {
854  return !(operator==(other) || operator<(other));
855  }
856 
875  bool Object::isVersionCompatibleTo(const Object& other) const {
876  if (this->version() == other.version())
877  return true;
878  if (this->version() > other.version())
879  return this->minVersion() <= other.version();
880  else
881  return other.minVersion() <= this->version();
882  }
883 
884  void Object::setVersion(Version v) {
885  m_version = v;
886  }
887 
888  void Object::setMinVersion(Version v) {
889  m_minVersion = v;
890  }
891 
921  Member Object::memberNamed(String name) const {
922  for (int i = 0; i < m_members.size(); ++i)
923  if (m_members[i].name() == name)
924  return m_members[i];
925  return Member();
926  }
927 
942  Member Object::memberByUID(const UID& uid) const {
943  if (!uid) return Member();
944  for (int i = 0; i < m_members.size(); ++i)
945  if (m_members[i].uid() == uid)
946  return m_members[i];
947  return Member();
948  }
949 
950  void Object::remove(const Member& member) {
951  for (int i = 0; i < m_members.size(); ++i) {
952  if (m_members[i] == member) {
953  m_members.erase(m_members.begin() + i);
954  return;
955  }
956  }
957  }
958 
974  std::vector<Member> Object::membersOfType(const DataType& type) const {
975  std::vector<Member> v;
976  for (int i = 0; i < m_members.size(); ++i) {
977  const Member& member = m_members[i];
978  if (member.type() == type)
979  v.push_back(member);
980  }
981  return v;
982  }
983 
1015  int Object::sequenceIndexOf(const Member& member) const {
1016  for (int i = 0; i < m_members.size(); ++i)
1017  if (m_members[i] == member)
1018  return i;
1019  return -1;
1020  }
1021 
1022  // *************** Archive ***************
1023  // *
1024 
1044  m_operation = OPERATION_NONE;
1045  m_root = NO_UID;
1046  m_isModified = false;
1047  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1048  }
1049 
1065  Archive::Archive(const RawData& data) {
1066  m_operation = OPERATION_NONE;
1067  m_root = NO_UID;
1068  m_isModified = false;
1069  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1070  decode(m_rawData);
1071  }
1072 
1093  Archive::Archive(const uint8_t* data, size_t size) {
1094  m_operation = OPERATION_NONE;
1095  m_root = NO_UID;
1096  m_isModified = false;
1097  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1098  decode(data, size);
1099  }
1100 
1101  Archive::~Archive() {
1102  }
1103 
1115  return m_allObjects[m_root];
1116  }
1117 
1118  static String _encodeBlob(String data) {
1119  return ToString(data.length()) + ":" + data;
1120  }
1121 
1122  static String _encode(const UID& uid) {
1123  String s;
1124  s += _encodeBlob(ToString(size_t(uid.id)));
1125  s += _encodeBlob(ToString(size_t(uid.size)));
1126  return _encodeBlob(s);
1127  }
1128 
1129  static String _encode(const time_t& time) {
1130  return _encodeBlob(ToString(time));
1131  }
1132 
1133  static String _encode(const DataType& type) {
1134  String s;
1135  s += _encodeBlob(type.baseTypeName());
1136  s += _encodeBlob(type.customTypeName());
1137  s += _encodeBlob(ToString(type.size()));
1138  s += _encodeBlob(ToString(type.isPointer()));
1139  return _encodeBlob(s);
1140  }
1141 
1142  static String _encode(const UIDChain& chain) {
1143  String s;
1144  for (int i = 0; i < chain.size(); ++i)
1145  s += _encode(chain[i]);
1146  return _encodeBlob(s);
1147  }
1148 
1149  static String _encode(const Member& member) {
1150  String s;
1151  s += _encode(member.uid());
1152  s += _encodeBlob(ToString(member.offset()));
1153  s += _encodeBlob(member.name());
1154  s += _encode(member.type());
1155  return _encodeBlob(s);
1156  }
1157 
1158  static String _encode(const std::vector<Member>& members) {
1159  String s;
1160  for (int i = 0; i < members.size(); ++i)
1161  s += _encode(members[i]);
1162  return _encodeBlob(s);
1163  }
1164 
1165  static String _primitiveObjectValueToString(const Object& obj) {
1166  String s;
1167  const DataType& type = obj.type();
1168  const ID& id = obj.uid().id;
1169  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1170  if (!obj.m_data.empty())
1171  assert(type.size() == obj.m_data.size());
1172  if (type.isPrimitive() && !type.isPointer()) {
1173  if (type.isInteger() || type.isEnum()) {
1174  if (type.isSigned()) {
1175  if (type.size() == 1)
1176  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1177  else if (type.size() == 2)
1178  s = ToString(*(int16_t*)ptr);
1179  else if (type.size() == 4)
1180  s = ToString(*(int32_t*)ptr);
1181  else if (type.size() == 8)
1182  s = ToString(*(int64_t*)ptr);
1183  else
1184  assert(false /* unknown signed int type size */);
1185  } else {
1186  if (type.size() == 1)
1187  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1188  else if (type.size() == 2)
1189  s = ToString(*(uint16_t*)ptr);
1190  else if (type.size() == 4)
1191  s = ToString(*(uint32_t*)ptr);
1192  else if (type.size() == 8)
1193  s = ToString(*(uint64_t*)ptr);
1194  else
1195  assert(false /* unknown unsigned int type size */);
1196  }
1197  } else if (type.isReal()) {
1198  if (type.size() == sizeof(float))
1199  s = ToString(*(float*)ptr);
1200  else if (type.size() == sizeof(double))
1201  s = ToString(*(double*)ptr);
1202  else
1203  assert(false /* unknown floating point type */);
1204  } else if (type.isBool()) {
1205  s = ToString(*(bool*)ptr);
1206  } else {
1207  assert(false /* unknown primitive type */);
1208  }
1209 
1210  }
1211  return s;
1212  }
1213 
1214  template<typename T>
1215  static T _primitiveObjectValueToNumber(const Object& obj) {
1216  T value = 0;
1217  const DataType& type = obj.type();
1218  const ID& id = obj.uid().id;
1219  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1220  if (!obj.m_data.empty())
1221  assert(type.size() == obj.m_data.size());
1222  if (type.isPrimitive() && !type.isPointer()) {
1223  if (type.isInteger() || type.isEnum()) {
1224  if (type.isSigned()) {
1225  if (type.size() == 1)
1226  value = (T)*(int8_t*)ptr;
1227  else if (type.size() == 2)
1228  value = (T)*(int16_t*)ptr;
1229  else if (type.size() == 4)
1230  value = (T)*(int32_t*)ptr;
1231  else if (type.size() == 8)
1232  value = (T)*(int64_t*)ptr;
1233  else
1234  assert(false /* unknown signed int type size */);
1235  } else {
1236  if (type.size() == 1)
1237  value = (T)*(uint8_t*)ptr;
1238  else if (type.size() == 2)
1239  value = (T)*(uint16_t*)ptr;
1240  else if (type.size() == 4)
1241  value = (T)*(uint32_t*)ptr;
1242  else if (type.size() == 8)
1243  value = (T)*(uint64_t*)ptr;
1244  else
1245  assert(false /* unknown unsigned int type size */);
1246  }
1247  } else if (type.isReal()) {
1248  if (type.size() == sizeof(float))
1249  value = (T)*(float*)ptr;
1250  else if (type.size() == sizeof(double))
1251  value = (T)*(double*)ptr;
1252  else
1253  assert(false /* unknown floating point type */);
1254  } else if (type.isBool()) {
1255  value = (T)*(bool*)ptr;
1256  } else {
1257  assert(false /* unknown primitive type */);
1258  }
1259  }
1260  return value;
1261  }
1262 
1263  static String _encodePrimitiveValue(const Object& obj) {
1264  return _encodeBlob( _primitiveObjectValueToString(obj) );
1265  }
1266 
1267  static String _encode(const Object& obj) {
1268  String s;
1269  s += _encode(obj.type());
1270  s += _encodeBlob(ToString(obj.version()));
1271  s += _encodeBlob(ToString(obj.minVersion()));
1272  s += _encode(obj.uidChain());
1273  s += _encode(obj.members());
1274  s += _encodePrimitiveValue(obj);
1275  return _encodeBlob(s);
1276  }
1277 
1278  String _encode(const Archive::ObjectPool& objects) {
1279  String s;
1280  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1281  itObject != objects.end(); ++itObject)
1282  {
1283  const Object& obj = itObject->second;
1284  s += _encode(obj);
1285  }
1286  return _encodeBlob(s);
1287  }
1288 
1289  #define MAGIC_START "Srx1v"
1290  #define ENCODING_FORMAT_MINOR_VERSION 0
1291 
1292  String Archive::_encodeRootBlob() {
1293  String s;
1294  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1295  s += _encode(m_root);
1296  s += _encode(m_allObjects);
1297  s += _encodeBlob(m_name);
1298  s += _encodeBlob(m_comment);
1299  s += _encode(m_timeCreated);
1300  s += _encode(m_timeModified);
1301  return _encodeBlob(s);
1302  }
1303 
1304  void Archive::encode() {
1305  m_rawData.clear();
1306  String s = MAGIC_START;
1307  m_timeModified = time(NULL);
1308  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1309  m_timeCreated = m_timeModified;
1310  s += _encodeRootBlob();
1311  m_rawData.resize(s.length() + 1);
1312  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1313  m_isModified = false;
1314  }
1315 
1316  struct _Blob {
1317  const char* p;
1318  const char* end;
1319  };
1320 
1321  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1322  if (!bThrow && p >= end) {
1323  const _Blob blob = { p, end };
1324  return blob;
1325  }
1326  size_t sz = 0;
1327  for (; true; ++p) {
1328  if (p >= end)
1329  throw Exception("Decode Error: Missing blob");
1330  const char& c = *p;
1331  if (c == ':') break;
1332  if (c < '0' || c > '9')
1333  throw Exception("Decode Error: Missing blob size");
1334  sz *= 10;
1335  sz += size_t(c - '0');
1336  }
1337  ++p;
1338  if (p + sz > end)
1339  throw Exception("Decode Error: Premature end of blob");
1340  const _Blob blob = { p, p + sz };
1341  return blob;
1342  }
1343 
1344  template<typename T_int>
1345  static T_int _popIntBlob(const char*& p, const char* end) {
1346  _Blob blob = _decodeBlob(p, end);
1347  p = blob.p;
1348  end = blob.end;
1349 
1350  T_int sign = 1;
1351  T_int i = 0;
1352  if (p >= end)
1353  throw Exception("Decode Error: premature end of int blob");
1354  if (*p == '-') {
1355  sign = -1;
1356  ++p;
1357  }
1358  for (; p < end; ++p) {
1359  const char& c = *p;
1360  if (c < '0' || c > '9')
1361  throw Exception("Decode Error: Invalid int blob format");
1362  i *= 10;
1363  i += size_t(c - '0');
1364  }
1365  return i * sign;
1366  }
1367 
1368  template<typename T_int>
1369  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1370  const T_int i = _popIntBlob<T_int>(p, end);
1371  *(T_int*)&rawData[0] = i;
1372  }
1373 
1374  template<typename T_real>
1375  static T_real _popRealBlob(const char*& p, const char* end) {
1376  _Blob blob = _decodeBlob(p, end);
1377  p = blob.p;
1378  end = blob.end;
1379 
1380  if (p >= end || (end - p) < 1)
1381  throw Exception("Decode Error: premature end of real blob");
1382 
1383  String s(p, size_t(end - p));
1384 
1385  T_real r;
1386  if (sizeof(T_real) <= sizeof(double))
1387  r = atof(s.c_str());
1388  else
1389  assert(false /* unknown real type */);
1390 
1391  p += s.length();
1392 
1393  return r;
1394  }
1395 
1396  template<typename T_real>
1397  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1398  const T_real r = _popRealBlob<T_real>(p, end);
1399  *(T_real*)&rawData[0] = r;
1400  }
1401 
1402  static String _popStringBlob(const char*& p, const char* end) {
1403  _Blob blob = _decodeBlob(p, end);
1404  p = blob.p;
1405  end = blob.end;
1406  if (end - p < 0)
1407  throw Exception("Decode Error: missing String blob");
1408  String s;
1409  const size_t sz = end - p;
1410  s.resize(sz);
1411  memcpy(&s[0], p, sz);
1412  p += sz;
1413  return s;
1414  }
1415 
1416  static time_t _popTimeBlob(const char*& p, const char* end) {
1417  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1418  return (time_t) i;
1419  }
1420 
1421  static DataType _popDataTypeBlob(const char*& p, const char* end) {
1422  _Blob blob = _decodeBlob(p, end);
1423  p = blob.p;
1424  end = blob.end;
1425 
1426  DataType type;
1427  type.m_baseTypeName = _popStringBlob(p, end);
1428  type.m_customTypeName = _popStringBlob(p, end);
1429  type.m_size = _popIntBlob<int>(p, end);
1430  type.m_isPointer = _popIntBlob<bool>(p, end);
1431  return type;
1432  }
1433 
1434  static UID _popUIDBlob(const char*& p, const char* end) {
1435  _Blob blob = _decodeBlob(p, end);
1436  p = blob.p;
1437  end = blob.end;
1438 
1439  if (p >= end)
1440  throw Exception("Decode Error: premature end of UID blob");
1441 
1442  const ID id = (ID) _popIntBlob<size_t>(p, end);
1443  const size_t size = _popIntBlob<size_t>(p, end);
1444 
1445  const UID uid = { id, size };
1446  return uid;
1447  }
1448 
1449  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1450  _Blob blob = _decodeBlob(p, end);
1451  p = blob.p;
1452  end = blob.end;
1453 
1454  UIDChain chain;
1455  while (p < end) {
1456  const UID uid = _popUIDBlob(p, end);
1457  chain.push_back(uid);
1458  }
1459  assert(!chain.empty());
1460  return chain;
1461  }
1462 
1463  static Member _popMemberBlob(const char*& p, const char* end) {
1464  _Blob blob = _decodeBlob(p, end, false);
1465  p = blob.p;
1466  end = blob.end;
1467 
1468  Member m;
1469  if (p >= end) return m;
1470 
1471  m.m_uid = _popUIDBlob(p, end);
1472  m.m_offset = _popIntBlob<size_t>(p, end);
1473  m.m_name = _popStringBlob(p, end);
1474  m.m_type = _popDataTypeBlob(p, end);
1475  assert(m.type());
1476  assert(!m.name().empty());
1477  assert(m.uid().isValid());
1478  return m;
1479  }
1480 
1481  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1482  _Blob blob = _decodeBlob(p, end, false);
1483  p = blob.p;
1484  end = blob.end;
1485 
1486  std::vector<Member> members;
1487  while (p < end) {
1488  const Member member = _popMemberBlob(p, end);
1489  if (member)
1490  members.push_back(member);
1491  else
1492  break;
1493  }
1494  return members;
1495  }
1496 
1497  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1498  const DataType& type = obj.type();
1499  if (type.isPrimitive() && !type.isPointer()) {
1500  obj.m_data.resize(type.size());
1501  if (type.isInteger() || type.isEnum()) {
1502  if (type.isSigned()) {
1503  if (type.size() == 1)
1504  _popIntBlob<int8_t>(p, end, obj.m_data);
1505  else if (type.size() == 2)
1506  _popIntBlob<int16_t>(p, end, obj.m_data);
1507  else if (type.size() == 4)
1508  _popIntBlob<int32_t>(p, end, obj.m_data);
1509  else if (type.size() == 8)
1510  _popIntBlob<int64_t>(p, end, obj.m_data);
1511  else
1512  assert(false /* unknown signed int type size */);
1513  } else {
1514  if (type.size() == 1)
1515  _popIntBlob<uint8_t>(p, end, obj.m_data);
1516  else if (type.size() == 2)
1517  _popIntBlob<uint16_t>(p, end, obj.m_data);
1518  else if (type.size() == 4)
1519  _popIntBlob<uint32_t>(p, end, obj.m_data);
1520  else if (type.size() == 8)
1521  _popIntBlob<uint64_t>(p, end, obj.m_data);
1522  else
1523  assert(false /* unknown unsigned int type size */);
1524  }
1525  } else if (type.isReal()) {
1526  if (type.size() == sizeof(float))
1527  _popRealBlob<float>(p, end, obj.m_data);
1528  else if (type.size() == sizeof(double))
1529  _popRealBlob<double>(p, end, obj.m_data);
1530  else
1531  assert(false /* unknown floating point type */);
1532  } else if (type.isBool()) {
1533  _popIntBlob<uint8_t>(p, end, obj.m_data);
1534  } else {
1535  assert(false /* unknown primitive type */);
1536  }
1537 
1538  } else {
1539  // don't whine if the empty blob was not added on encoder side
1540  _Blob blob = _decodeBlob(p, end, false);
1541  p = blob.p;
1542  end = blob.end;
1543  }
1544  }
1545 
1546  static Object _popObjectBlob(const char*& p, const char* end) {
1547  _Blob blob = _decodeBlob(p, end, false);
1548  p = blob.p;
1549  end = blob.end;
1550 
1551  Object obj;
1552  if (p >= end) return obj;
1553 
1554  obj.m_type = _popDataTypeBlob(p, end);
1555  obj.m_version = _popIntBlob<Version>(p, end);
1556  obj.m_minVersion = _popIntBlob<Version>(p, end);
1557  obj.m_uid = _popUIDChainBlob(p, end);
1558  obj.m_members = _popMembersBlob(p, end);
1559  _popPrimitiveValue(p, end, obj);
1560  assert(obj.type());
1561  return obj;
1562  }
1563 
1564  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1565  _Blob blob = _decodeBlob(p, end, false);
1566  p = blob.p;
1567  end = blob.end;
1568 
1569  if (p >= end)
1570  throw Exception("Decode Error: Premature end of objects blob");
1571 
1572  while (true) {
1573  const Object obj = _popObjectBlob(p, end);
1574  if (!obj) break;
1575  m_allObjects[obj.uid()] = obj;
1576  }
1577  }
1578 
1579  void Archive::_popRootBlob(const char*& p, const char* end) {
1580  _Blob blob = _decodeBlob(p, end, false);
1581  p = blob.p;
1582  end = blob.end;
1583 
1584  if (p >= end)
1585  throw Exception("Decode Error: Premature end of root blob");
1586 
1587  // just in case this encoding format will be extended in future
1588  // (currently not used)
1589  const int formatMinorVersion = _popIntBlob<int>(p, end);
1590 
1591  m_root = _popUIDBlob(p, end);
1592  if (!m_root)
1593  throw Exception("Decode Error: No root object");
1594 
1595  _popObjectsBlob(p, end);
1596  if (!m_allObjects[m_root])
1597  throw Exception("Decode Error: Missing declared root object");
1598 
1599  m_name = _popStringBlob(p, end);
1600  m_comment = _popStringBlob(p, end);
1601  m_timeCreated = _popTimeBlob(p, end);
1602  m_timeModified = _popTimeBlob(p, end);
1603  }
1604 
1620  void Archive::decode(const RawData& data) {
1621  m_rawData = data;
1622  m_allObjects.clear();
1623  m_isModified = false;
1624  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1625  const char* p = (const char*) &data[0];
1626  const char* end = p + data.size();
1627  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1628  throw Exception("Decode Error: Magic start missing!");
1629  p += strlen(MAGIC_START);
1630  _popRootBlob(p, end);
1631  }
1632 
1653  void Archive::decode(const uint8_t* data, size_t size) {
1654  RawData rawData;
1655  rawData.resize(size);
1656  memcpy(&rawData[0], data, size);
1657  decode(rawData);
1658  }
1659 
1676  if (m_isModified) encode();
1677  return m_rawData;
1678  }
1679 
1685  String Archive::rawDataFormat() const {
1686  return MAGIC_START;
1687  }
1688 
1703  bool Archive::isModified() const {
1704  return m_isModified;
1705  }
1706 
1713  m_allObjects.clear();
1714  m_operation = OPERATION_NONE;
1715  m_root = NO_UID;
1716  m_rawData.clear();
1717  m_isModified = false;
1718  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1719  }
1720 
1728  String Archive::name() const {
1729  return m_name;
1730  }
1731 
1741  void Archive::setName(String name) {
1742  if (m_name == name) return;
1743  m_name = name;
1744  m_isModified = true;
1745  }
1746 
1754  String Archive::comment() const {
1755  return m_comment;
1756  }
1757 
1767  void Archive::setComment(String comment) {
1768  if (m_comment == comment) return;
1769  m_comment = comment;
1770  m_isModified = true;
1771  }
1772 
1773  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1774  tm* pTm;
1775  switch (base) {
1776  case LOCAL_TIME:
1777  pTm = localtime(&time);
1778  break;
1779  case UTC_TIME:
1780  pTm = gmtime(&time);
1781  break;
1782  default:
1783  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1784  }
1785  if (!pTm)
1786  throw Exception("Failed assembling time stamp structure");
1787  return *pTm;
1788  }
1789 
1795  time_t Archive::timeStampCreated() const {
1796  return m_timeCreated;
1797  }
1798 
1805  return m_timeModified;
1806  }
1807 
1819  return _convertTimeStamp(m_timeCreated, base);
1820  }
1821 
1833  return _convertTimeStamp(m_timeModified, base);
1834  }
1835 
1853  void Archive::removeMember(Object& parent, const Member& member) {
1854  parent.remove(member);
1855  m_isModified = true;
1856  }
1857 
1873  void Archive::remove(const Object& obj) {
1874  //FIXME: Should traverse from root object and remove all members associated with this object
1875  if (!obj.uid()) return;
1876  m_allObjects.erase(obj.uid());
1877  m_isModified = true;
1878  }
1879 
1892  return m_allObjects[uid];
1893  }
1894 
1906  if (!object) return;
1907  object.setVersion(v);
1908  m_isModified = true;
1909  }
1910 
1922  if (!object) return;
1923  object.setMinVersion(v);
1924  m_isModified = true;
1925  }
1926 
1935  void Archive::setEnumValue(Object& object, uint64_t value) {
1936  if (!object) return;
1937  if (!object.type().isEnum())
1938  throw Exception("Not an enum data type");
1939  Object* pObject = &object;
1940  if (object.type().isPointer()) {
1941  Object& obj = objectByUID(object.uid(1));
1942  if (!obj) return;
1943  pObject = &obj;
1944  }
1945  const int nativeEnumSize = sizeof(enum operation_t);
1946  DataType& type = const_cast<DataType&>( pObject->type() );
1947  // original serializer ("sender") might have had a different word size
1948  // than this machine, adjust type object in this case
1949  if (type.size() != nativeEnumSize) {
1950  type.m_size = nativeEnumSize;
1951  }
1952  pObject->m_data.resize(type.size());
1953  void* ptr = &pObject->m_data[0];
1954  if (type.size() == 1)
1955  *(uint8_t*)ptr = (uint8_t)value;
1956  else if (type.size() == 2)
1957  *(uint16_t*)ptr = (uint16_t)value;
1958  else if (type.size() == 4)
1959  *(uint32_t*)ptr = (uint32_t)value;
1960  else if (type.size() == 8)
1961  *(uint64_t*)ptr = (uint64_t)value;
1962  else
1963  assert(false /* unknown enum type size */);
1964  m_isModified = true;
1965  }
1966 
1977  void Archive::setIntValue(Object& object, int64_t value) {
1978  if (!object) return;
1979  if (!object.type().isInteger())
1980  throw Exception("Not an integer data type");
1981  Object* pObject = &object;
1982  if (object.type().isPointer()) {
1983  Object& obj = objectByUID(object.uid(1));
1984  if (!obj) return;
1985  pObject = &obj;
1986  }
1987  const DataType& type = pObject->type();
1988  pObject->m_data.resize(type.size());
1989  void* ptr = &pObject->m_data[0];
1990  if (type.isSigned()) {
1991  if (type.size() == 1)
1992  *(int8_t*)ptr = (int8_t)value;
1993  else if (type.size() == 2)
1994  *(int16_t*)ptr = (int16_t)value;
1995  else if (type.size() == 4)
1996  *(int32_t*)ptr = (int32_t)value;
1997  else if (type.size() == 8)
1998  *(int64_t*)ptr = (int64_t)value;
1999  else
2000  assert(false /* unknown signed int type size */);
2001  } else {
2002  if (type.size() == 1)
2003  *(uint8_t*)ptr = (uint8_t)value;
2004  else if (type.size() == 2)
2005  *(uint16_t*)ptr = (uint16_t)value;
2006  else if (type.size() == 4)
2007  *(uint32_t*)ptr = (uint32_t)value;
2008  else if (type.size() == 8)
2009  *(uint64_t*)ptr = (uint64_t)value;
2010  else
2011  assert(false /* unknown unsigned int type size */);
2012  }
2013  m_isModified = true;
2014  }
2015 
2027  void Archive::setRealValue(Object& object, double value) {
2028  if (!object) return;
2029  if (!object.type().isReal())
2030  throw Exception("Not a real data type");
2031  Object* pObject = &object;
2032  if (object.type().isPointer()) {
2033  Object& obj = objectByUID(object.uid(1));
2034  if (!obj) return;
2035  pObject = &obj;
2036  }
2037  const DataType& type = pObject->type();
2038  pObject->m_data.resize(type.size());
2039  void* ptr = &pObject->m_data[0];
2040  if (type.size() == sizeof(float))
2041  *(float*)ptr = (float)value;
2042  else if (type.size() == sizeof(double))
2043  *(double*)ptr = (double)value;
2044  else
2045  assert(false /* unknown real type size */);
2046  m_isModified = true;
2047  }
2048 
2057  void Archive::setBoolValue(Object& object, bool value) {
2058  if (!object) return;
2059  if (!object.type().isBool())
2060  throw Exception("Not a bool data type");
2061  Object* pObject = &object;
2062  if (object.type().isPointer()) {
2063  Object& obj = objectByUID(object.uid(1));
2064  if (!obj) return;
2065  pObject = &obj;
2066  }
2067  const DataType& type = pObject->type();
2068  pObject->m_data.resize(type.size());
2069  bool* ptr = (bool*)&pObject->m_data[0];
2070  *ptr = value;
2071  m_isModified = true;
2072  }
2073 
2087  void Archive::setAutoValue(Object& object, String value) {
2088  if (!object) return;
2089  const DataType& type = object.type();
2090  if (type.isInteger())
2091  setIntValue(object, atoll(value.c_str()));
2092  else if (type.isReal())
2093  setRealValue(object, atof(value.c_str()));
2094  else if (type.isBool()) {
2095  String val = toLowerCase(value);
2096  if (val == "true" || val == "yes" || val == "1")
2097  setBoolValue(object, true);
2098  else if (val == "false" || val == "no" || val == "0")
2099  setBoolValue(object, false);
2100  else
2101  setBoolValue(object, atof(value.c_str()));
2102  } else if (type.isEnum())
2103  setEnumValue(object, atoll(value.c_str()));
2104  else
2105  throw Exception("Not a primitive data type");
2106  }
2107 
2117  String Archive::valueAsString(const Object& object) {
2118  if (!object)
2119  throw Exception("Invalid object");
2120  if (object.type().isClass())
2121  throw Exception("Object is class type");
2122  const Object* pObject = &object;
2123  if (object.type().isPointer()) {
2124  const Object& obj = objectByUID(object.uid(1));
2125  if (!obj) return "";
2126  pObject = &obj;
2127  }
2128  return _primitiveObjectValueToString(*pObject);
2129  }
2130 
2140  int64_t Archive::valueAsInt(const Object& object) {
2141  if (!object)
2142  throw Exception("Invalid object");
2143  if (!object.type().isInteger() && !object.type().isEnum())
2144  throw Exception("Object is neither an integer nor an enum");
2145  const Object* pObject = &object;
2146  if (object.type().isPointer()) {
2147  const Object& obj = objectByUID(object.uid(1));
2148  if (!obj) return 0;
2149  pObject = &obj;
2150  }
2151  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2152  }
2153 
2163  double Archive::valueAsReal(const Object& object) {
2164  if (!object)
2165  throw Exception("Invalid object");
2166  if (!object.type().isReal())
2167  throw Exception("Object is not an real type");
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<double>(*pObject);
2175  }
2176 
2185  bool Archive::valueAsBool(const Object& object) {
2186  if (!object)
2187  throw Exception("Invalid object");
2188  if (!object.type().isBool())
2189  throw Exception("Object is not a bool");
2190  const Object* pObject = &object;
2191  if (object.type().isPointer()) {
2192  const Object& obj = objectByUID(object.uid(1));
2193  if (!obj) return 0;
2194  pObject = &obj;
2195  }
2196  return _primitiveObjectValueToNumber<bool>(*pObject);
2197  }
2198 
2199  // *************** Archive::Syncer ***************
2200  // *
2201 
2202  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2203  : m_dst(dst), m_src(src)
2204  {
2205  const Object srcRootObj = src.rootObject();
2206  const Object dstRootObj = dst.rootObject();
2207  if (!srcRootObj)
2208  throw Exception("No source root object!");
2209  if (!dstRootObj)
2210  throw Exception("Expected destination root object not found!");
2211  syncObject(dstRootObj, srcRootObj);
2212  }
2213 
2214  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2215  assert(srcObj.rawData().size() == dstObj.type().size());
2216  void* pDst = (void*)dstObj.uid().id;
2217  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2218  }
2219 
2220  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2221  assert(dstObj.type().isPointer());
2222  assert(dstObj.type() == srcObj.type());
2223  const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2224  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2225  syncObject(pointedDstObject, pointedSrcObject);
2226  }
2227 
2228  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2229  if (!dstObj || !srcObj) return; // end of recursion
2230  if (!dstObj.isVersionCompatibleTo(srcObj))
2231  throw Exception("Version incompatible (destination version " +
2232  ToString(dstObj.version()) + " [min. version " +
2233  ToString(dstObj.minVersion()) + "], source version " +
2234  ToString(srcObj.version()) + " [min. version " +
2235  ToString(srcObj.minVersion()) + "])");
2236  if (dstObj.type() != srcObj.type())
2237  throw Exception("Incompatible data structure type (destination type " +
2238  dstObj.type().asLongDescr() + " vs. source type " +
2239  srcObj.type().asLongDescr() + ")");
2240 
2241  // prevent syncing this object again, and thus also prevent endless
2242  // loop on data structures with cyclic relations
2243  m_dst.m_allObjects.erase(dstObj.uid());
2244 
2245  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2246  syncPrimitive(dstObj, srcObj);
2247  return; // end of recursion
2248  }
2249 
2250  if (dstObj.type().isPointer()) {
2251  syncPointer(dstObj, srcObj);
2252  return;
2253  }
2254 
2255  assert(dstObj.type().isClass());
2256  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2257  const Member& srcMember = srcObj.members()[iMember];
2258  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2259  if (!dstMember)
2260  throw Exception("Expected member missing in destination object");
2261  syncMember(dstMember, srcMember);
2262  }
2263  }
2264 
2265  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2266  Member dstMember = dstObj.memberNamed(srcMember.name());
2267  if (dstMember)
2268  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2269  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2270  if (members.size() <= 0)
2271  return Member();
2272  if (members.size() == 1)
2273  return members[0];
2274  for (int i = 0; i < members.size(); ++i)
2275  if (members[i].offset() == srcMember.offset())
2276  return members[i];
2277  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2278  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2279  for (int i = 0; i < members.size(); ++i) {
2280  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2281  if (dstSeqNr == srcSeqNr)
2282  return members[i];
2283  }
2284  return Member(); // give up!
2285  }
2286 
2287  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2288  assert(dstMember && srcMember);
2289  assert(dstMember.type() == srcMember.type());
2290  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2291  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2292  syncObject(dstObj, srcObj);
2293  }
2294 
2295  // *************** Exception ***************
2296  // *
2297 
2298  Exception::Exception() {
2299  }
2300 
2301  Exception::Exception(String format, ...) {
2302  va_list arg;
2303  va_start(arg, format);
2304  Message = assemble(format, arg);
2305  va_end(arg);
2306  }
2307 
2308  Exception::Exception(String format, va_list arg) {
2309  Message = assemble(format, arg);
2310  }
2311 
2318  std::cout << "Serialization::Exception: " << Message << std::endl;
2319  }
2320 
2321  String Exception::assemble(String format, va_list arg) {
2322  char* buf = NULL;
2323  vasprintf(&buf, format.c_str(), arg);
2324  String s = buf;
2325  free(buf);
2326  return s;
2327  }
2328 
2329 } // 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.
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'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'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.