libgig  4.1.0
Serialization.cpp
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017 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 #include "Serialization.h"
25 
26 #include <iostream>
27 #include <assert.h>
28 #include <string.h> // for memcpy()
29 #include <stdlib.h> // for atof()
30 #include <cxxabi.h>
31 
32 #include "helper.h"
33 
34 #define LIBGIG_EPOCH_TIME ((time_t)0)
35 
36 namespace Serialization {
37 
38  // *************** DataType ***************
39  // *
40 
41  static UID _createNullUID() {
42  const UID uid = { NULL, 0 };
43  return uid;
44  }
45 
46  const UID NO_UID = _createNullUID();
47 
59  bool UID::isValid() const {
60  return id != NULL && id != (void*)-1 && size;
61  }
62 
63  // *************** DataType ***************
64  // *
65 
76  m_size = 0;
77  m_isPointer = false;
78  }
79 
80  DataType::DataType(bool isPointer, int size, String baseType, String customType) {
81  m_size = size;
82  m_isPointer = isPointer;
83  m_baseTypeName = baseType;
84  m_customTypeName = customType;
85  }
86 
97  bool DataType::isValid() const {
98  return m_size;
99  }
100 
106  bool DataType::isPointer() const {
107  return m_isPointer;
108  }
109 
130  bool DataType::isClass() const {
131  return m_baseTypeName == "class";
132  }
133 
154  bool DataType::isPrimitive() const {
155  return !isClass();
156  }
157 
172  bool DataType::isInteger() const {
173  return m_baseTypeName.substr(0, 3) == "int" ||
174  m_baseTypeName.substr(0, 4) == "uint";
175  }
176 
189  bool DataType::isReal() const {
190  return m_baseTypeName.substr(0, 4) == "real";
191  }
192 
204  bool DataType::isBool() const {
205  return m_baseTypeName == "bool";
206  }
207 
219  bool DataType::isEnum() const {
220  return m_baseTypeName == "enum";
221  }
222 
236  bool DataType::isSigned() const {
237  return m_baseTypeName.substr(0, 3) == "int" ||
238  isReal();
239  }
240 
259  bool DataType::operator==(const DataType& other) const {
260  return m_baseTypeName == other.m_baseTypeName &&
261  m_customTypeName == other.m_customTypeName &&
262  (m_size == other.m_size || (isClass() && other.isClass())) &&
263  m_isPointer == other.m_isPointer;
264  }
265 
271  bool DataType::operator!=(const DataType& other) const {
272  return !operator==(other);
273  }
274 
286  bool DataType::operator<(const DataType& other) const {
287  return m_baseTypeName < other.m_baseTypeName ||
288  (m_baseTypeName == other.m_baseTypeName &&
289  m_customTypeName < other.m_customTypeName ||
290  (m_customTypeName == other.m_customTypeName &&
291  m_size < other.m_size ||
292  (m_size == other.m_size &&
293  m_isPointer < other.m_isPointer)));
294  }
295 
307  bool DataType::operator>(const DataType& other) const {
308  return !(operator==(other) || operator<(other));
309  }
310 
325  String DataType::asLongDescr() const {
326  String s = m_baseTypeName;
327  if (!m_customTypeName.empty())
328  s += " " + customTypeName(true);
329  if (isPointer())
330  s += " pointer";
331  return s;
332  }
333 
363  String DataType::baseTypeName() const {
364  return m_baseTypeName;
365  }
366 
400  String DataType::customTypeName(bool demangle) const {
401  if (!demangle) return m_customTypeName;
402  int status;
403  const char* result =
404  abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
405  return (status == 0) ? result : m_customTypeName;
406  }
407 
408  // *************** Member ***************
409  // *
410 
424  m_uid = NO_UID;
425  m_offset = 0;
426  }
427 
428  Member::Member(String name, UID uid, size_t offset, DataType type) {
429  m_name = name;
430  m_uid = uid;
431  m_offset = offset;
432  m_type = type;
433  }
434 
449  UID Member::uid() const {
450  return m_uid;
451  }
452 
473  String Member::name() const {
474  return m_name;
475  }
476 
511  size_t Member::offset() const {
512  return m_offset;
513  }
514 
519  const DataType& Member::type() const {
520  return m_type;
521  }
522 
533  bool Member::isValid() const {
534  return m_uid && !m_name.empty() && m_type;
535  }
536 
545  bool Member::operator==(const Member& other) const {
546  return m_uid == other.m_uid &&
547  m_offset == other.m_offset &&
548  m_name == other.m_name &&
549  m_type == other.m_type;
550  }
551 
557  bool Member::operator!=(const Member& other) const {
558  return !operator==(other);
559  }
560 
573  bool Member::operator<(const Member& other) const {
574  return m_uid < other.m_uid ||
575  (m_uid == other.m_uid &&
576  m_offset < other.m_offset ||
577  (m_offset == other.m_offset &&
578  m_name < other.m_name ||
579  (m_name == other.m_name &&
580  m_type < other.m_type)));
581  }
582 
595  bool Member::operator>(const Member& other) const {
596  return !(operator==(other) || operator<(other));
597  }
598 
599  // *************** Object ***************
600  // *
601 
614  m_version = 0;
615  m_minVersion = 0;
616  }
617 
635  Object::Object(UIDChain uidChain, DataType type) {
636  m_type = type;
637  m_uid = uidChain;
638  m_version = 0;
639  m_minVersion = 0;
640  //m_data.resize(type.size());
641  }
642 
653  bool Object::isValid() const {
654  return m_type && !m_uid.empty();
655  }
656 
668  UID Object::uid(int index) const {
669  return (index < m_uid.size()) ? m_uid[index] : NO_UID;
670  }
671 
678  const UIDChain& Object::uidChain() const {
679  return m_uid;
680  }
681 
687  const DataType& Object::type() const {
688  return m_type;
689  }
690 
713  const RawData& Object::rawData() const {
714  return m_data;
715  }
716 
727  return m_version;
728  }
729 
742  return m_minVersion;
743  }
744 
777  std::vector<Member>& Object::members() {
778  return m_members;
779  }
780 
787  const std::vector<Member>& Object::members() const {
788  return m_members;
789  }
790 
801  bool Object::operator==(const Object& other) const {
802  // ignoring all other member variables here
803  // (since UID stands for "unique" ;-) )
804  return m_uid == other.m_uid &&
805  m_type == other.m_type;
806  }
807 
813  bool Object::operator!=(const Object& other) const {
814  return !operator==(other);
815  }
816 
829  bool Object::operator<(const Object& other) const {
830  // ignoring all other member variables here
831  // (since UID stands for "unique" ;-) )
832  return m_uid < other.m_uid ||
833  (m_uid == other.m_uid &&
834  m_type < other.m_type);
835  }
836 
849  bool Object::operator>(const Object& other) const {
850  return !(operator==(other) || operator<(other));
851  }
852 
871  bool Object::isVersionCompatibleTo(const Object& other) const {
872  if (this->version() == other.version())
873  return true;
874  if (this->version() > other.version())
875  return this->minVersion() <= other.version();
876  else
877  return other.minVersion() <= this->version();
878  }
879 
880  void Object::setVersion(Version v) {
881  m_version = v;
882  }
883 
884  void Object::setMinVersion(Version v) {
885  m_minVersion = v;
886  }
887 
917  Member Object::memberNamed(String name) const {
918  for (int i = 0; i < m_members.size(); ++i)
919  if (m_members[i].name() == name)
920  return m_members[i];
921  return Member();
922  }
923 
938  Member Object::memberByUID(const UID& uid) const {
939  if (!uid) return Member();
940  for (int i = 0; i < m_members.size(); ++i)
941  if (m_members[i].uid() == uid)
942  return m_members[i];
943  return Member();
944  }
945 
946  void Object::remove(const Member& member) {
947  for (int i = 0; i < m_members.size(); ++i) {
948  if (m_members[i] == member) {
949  m_members.erase(m_members.begin() + i);
950  return;
951  }
952  }
953  }
954 
970  std::vector<Member> Object::membersOfType(const DataType& type) const {
971  std::vector<Member> v;
972  for (int i = 0; i < m_members.size(); ++i) {
973  const Member& member = m_members[i];
974  if (member.type() == type)
975  v.push_back(member);
976  }
977  return v;
978  }
979 
1011  int Object::sequenceIndexOf(const Member& member) const {
1012  for (int i = 0; i < m_members.size(); ++i)
1013  if (m_members[i] == member)
1014  return i;
1015  return -1;
1016  }
1017 
1018  // *************** Archive ***************
1019  // *
1020 
1040  m_operation = OPERATION_NONE;
1041  m_root = NO_UID;
1042  m_isModified = false;
1043  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1044  }
1045 
1061  Archive::Archive(const RawData& data) {
1062  m_operation = OPERATION_NONE;
1063  m_root = NO_UID;
1064  m_isModified = false;
1065  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1066  decode(m_rawData);
1067  }
1068 
1089  Archive::Archive(const uint8_t* data, size_t size) {
1090  m_operation = OPERATION_NONE;
1091  m_root = NO_UID;
1092  m_isModified = false;
1093  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1094  decode(data, size);
1095  }
1096 
1097  Archive::~Archive() {
1098  }
1099 
1111  return m_allObjects[m_root];
1112  }
1113 
1114  static String _encodeBlob(String data) {
1115  return ToString(data.length()) + ":" + data;
1116  }
1117 
1118  static String _encode(const UID& uid) {
1119  String s;
1120  s += _encodeBlob(ToString(size_t(uid.id)));
1121  s += _encodeBlob(ToString(size_t(uid.size)));
1122  return _encodeBlob(s);
1123  }
1124 
1125  static String _encode(const time_t& time) {
1126  return _encodeBlob(ToString(time));
1127  }
1128 
1129  static String _encode(const DataType& type) {
1130  String s;
1131  s += _encodeBlob(type.baseTypeName());
1132  s += _encodeBlob(type.customTypeName());
1133  s += _encodeBlob(ToString(type.size()));
1134  s += _encodeBlob(ToString(type.isPointer()));
1135  return _encodeBlob(s);
1136  }
1137 
1138  static String _encode(const UIDChain& chain) {
1139  String s;
1140  for (int i = 0; i < chain.size(); ++i)
1141  s += _encode(chain[i]);
1142  return _encodeBlob(s);
1143  }
1144 
1145  static String _encode(const Member& member) {
1146  String s;
1147  s += _encode(member.uid());
1148  s += _encodeBlob(ToString(member.offset()));
1149  s += _encodeBlob(member.name());
1150  s += _encode(member.type());
1151  return _encodeBlob(s);
1152  }
1153 
1154  static String _encode(const std::vector<Member>& members) {
1155  String s;
1156  for (int i = 0; i < members.size(); ++i)
1157  s += _encode(members[i]);
1158  return _encodeBlob(s);
1159  }
1160 
1161  static String _primitiveObjectValueToString(const Object& obj) {
1162  String s;
1163  const DataType& type = obj.type();
1164  const ID& id = obj.uid().id;
1165  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1166  if (!obj.m_data.empty())
1167  assert(type.size() == obj.m_data.size());
1168  if (type.isPrimitive() && !type.isPointer()) {
1169  if (type.isInteger() || type.isEnum()) {
1170  if (type.isSigned()) {
1171  if (type.size() == 1)
1172  s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1173  else if (type.size() == 2)
1174  s = ToString(*(int16_t*)ptr);
1175  else if (type.size() == 4)
1176  s = ToString(*(int32_t*)ptr);
1177  else if (type.size() == 8)
1178  s = ToString(*(int64_t*)ptr);
1179  else
1180  assert(false /* unknown signed int type size */);
1181  } else {
1182  if (type.size() == 1)
1183  s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1184  else if (type.size() == 2)
1185  s = ToString(*(uint16_t*)ptr);
1186  else if (type.size() == 4)
1187  s = ToString(*(uint32_t*)ptr);
1188  else if (type.size() == 8)
1189  s = ToString(*(uint64_t*)ptr);
1190  else
1191  assert(false /* unknown unsigned int type size */);
1192  }
1193  } else if (type.isReal()) {
1194  if (type.size() == sizeof(float))
1195  s = ToString(*(float*)ptr);
1196  else if (type.size() == sizeof(double))
1197  s = ToString(*(double*)ptr);
1198  else
1199  assert(false /* unknown floating point type */);
1200  } else if (type.isBool()) {
1201  s = ToString(*(bool*)ptr);
1202  } else {
1203  assert(false /* unknown primitive type */);
1204  }
1205 
1206  }
1207  return s;
1208  }
1209 
1210  template<typename T>
1211  static T _primitiveObjectValueToNumber(const Object& obj) {
1212  T value = 0;
1213  const DataType& type = obj.type();
1214  const ID& id = obj.uid().id;
1215  void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1216  if (!obj.m_data.empty())
1217  assert(type.size() == obj.m_data.size());
1218  if (type.isPrimitive() && !type.isPointer()) {
1219  if (type.isInteger() || type.isEnum()) {
1220  if (type.isSigned()) {
1221  if (type.size() == 1)
1222  value = (T)*(int8_t*)ptr;
1223  else if (type.size() == 2)
1224  value = (T)*(int16_t*)ptr;
1225  else if (type.size() == 4)
1226  value = (T)*(int32_t*)ptr;
1227  else if (type.size() == 8)
1228  value = (T)*(int64_t*)ptr;
1229  else
1230  assert(false /* unknown signed int type size */);
1231  } else {
1232  if (type.size() == 1)
1233  value = (T)*(uint8_t*)ptr;
1234  else if (type.size() == 2)
1235  value = (T)*(uint16_t*)ptr;
1236  else if (type.size() == 4)
1237  value = (T)*(uint32_t*)ptr;
1238  else if (type.size() == 8)
1239  value = (T)*(uint64_t*)ptr;
1240  else
1241  assert(false /* unknown unsigned int type size */);
1242  }
1243  } else if (type.isReal()) {
1244  if (type.size() == sizeof(float))
1245  value = (T)*(float*)ptr;
1246  else if (type.size() == sizeof(double))
1247  value = (T)*(double*)ptr;
1248  else
1249  assert(false /* unknown floating point type */);
1250  } else if (type.isBool()) {
1251  value = (T)*(bool*)ptr;
1252  } else {
1253  assert(false /* unknown primitive type */);
1254  }
1255  }
1256  return value;
1257  }
1258 
1259  static String _encodePrimitiveValue(const Object& obj) {
1260  return _encodeBlob( _primitiveObjectValueToString(obj) );
1261  }
1262 
1263  static String _encode(const Object& obj) {
1264  String s;
1265  s += _encode(obj.type());
1266  s += _encodeBlob(ToString(obj.version()));
1267  s += _encodeBlob(ToString(obj.minVersion()));
1268  s += _encode(obj.uidChain());
1269  s += _encode(obj.members());
1270  s += _encodePrimitiveValue(obj);
1271  return _encodeBlob(s);
1272  }
1273 
1274  String _encode(const Archive::ObjectPool& objects) {
1275  String s;
1276  for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1277  itObject != objects.end(); ++itObject)
1278  {
1279  const Object& obj = itObject->second;
1280  s += _encode(obj);
1281  }
1282  return _encodeBlob(s);
1283  }
1284 
1285  #define MAGIC_START "Srx1v"
1286  #define ENCODING_FORMAT_MINOR_VERSION 0
1287 
1288  String Archive::_encodeRootBlob() {
1289  String s;
1290  s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1291  s += _encode(m_root);
1292  s += _encode(m_allObjects);
1293  s += _encodeBlob(m_name);
1294  s += _encodeBlob(m_comment);
1295  s += _encode(m_timeCreated);
1296  s += _encode(m_timeModified);
1297  return _encodeBlob(s);
1298  }
1299 
1300  void Archive::encode() {
1301  m_rawData.clear();
1302  String s = MAGIC_START;
1303  m_timeModified = time(NULL);
1304  if (m_timeCreated == LIBGIG_EPOCH_TIME)
1305  m_timeCreated = m_timeModified;
1306  s += _encodeRootBlob();
1307  m_rawData.resize(s.length() + 1);
1308  memcpy(&m_rawData[0], &s[0], s.length() + 1);
1309  m_isModified = false;
1310  }
1311 
1312  struct _Blob {
1313  const char* p;
1314  const char* end;
1315  };
1316 
1317  static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1318  if (!bThrow && p >= end) {
1319  const _Blob blob = { p, end };
1320  return blob;
1321  }
1322  size_t sz = 0;
1323  for (; true; ++p) {
1324  if (p >= end)
1325  throw Exception("Decode Error: Missing blob");
1326  const char& c = *p;
1327  if (c == ':') break;
1328  if (c < '0' || c > '9')
1329  throw Exception("Decode Error: Missing blob size");
1330  sz *= 10;
1331  sz += size_t(c - '0');
1332  }
1333  ++p;
1334  if (p + sz > end)
1335  throw Exception("Decode Error: Premature end of blob");
1336  const _Blob blob = { p, p + sz };
1337  return blob;
1338  }
1339 
1340  template<typename T_int>
1341  static T_int _popIntBlob(const char*& p, const char* end) {
1342  _Blob blob = _decodeBlob(p, end);
1343  p = blob.p;
1344  end = blob.end;
1345 
1346  T_int sign = 1;
1347  T_int i = 0;
1348  if (p >= end)
1349  throw Exception("Decode Error: premature end of int blob");
1350  if (*p == '-') {
1351  sign = -1;
1352  ++p;
1353  }
1354  for (; p < end; ++p) {
1355  const char& c = *p;
1356  if (c < '0' || c > '9')
1357  throw Exception("Decode Error: Invalid int blob format");
1358  i *= 10;
1359  i += size_t(c - '0');
1360  }
1361  return i * sign;
1362  }
1363 
1364  template<typename T_int>
1365  static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1366  const T_int i = _popIntBlob<T_int>(p, end);
1367  *(T_int*)&rawData[0] = i;
1368  }
1369 
1370  template<typename T_real>
1371  static T_real _popRealBlob(const char*& p, const char* end) {
1372  _Blob blob = _decodeBlob(p, end);
1373  p = blob.p;
1374  end = blob.end;
1375 
1376  if (p >= end || (end - p) < 1)
1377  throw Exception("Decode Error: premature end of real blob");
1378 
1379  String s(p, size_t(end - p));
1380 
1381  T_real r;
1382  if (sizeof(T_real) <= sizeof(double))
1383  r = atof(s.c_str());
1384  else
1385  assert(false /* unknown real type */);
1386 
1387  p += s.length();
1388 
1389  return r;
1390  }
1391 
1392  template<typename T_real>
1393  static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1394  const T_real r = _popRealBlob<T_real>(p, end);
1395  *(T_real*)&rawData[0] = r;
1396  }
1397 
1398  static String _popStringBlob(const char*& p, const char* end) {
1399  _Blob blob = _decodeBlob(p, end);
1400  p = blob.p;
1401  end = blob.end;
1402  if (end - p < 0)
1403  throw Exception("Decode Error: missing String blob");
1404  String s;
1405  const size_t sz = end - p;
1406  s.resize(sz);
1407  memcpy(&s[0], p, sz);
1408  p += sz;
1409  return s;
1410  }
1411 
1412  static time_t _popTimeBlob(const char*& p, const char* end) {
1413  const uint64_t i = _popIntBlob<uint64_t>(p, end);
1414  return (time_t) i;
1415  }
1416 
1417  DataType _popDataTypeBlob(const char*& p, const char* end) {
1418  _Blob blob = _decodeBlob(p, end);
1419  p = blob.p;
1420  end = blob.end;
1421 
1422  DataType type;
1423  type.m_baseTypeName = _popStringBlob(p, end);
1424  type.m_customTypeName = _popStringBlob(p, end);
1425  type.m_size = _popIntBlob<int>(p, end);
1426  type.m_isPointer = _popIntBlob<bool>(p, end);
1427  return type;
1428  }
1429 
1430  static UID _popUIDBlob(const char*& p, const char* end) {
1431  _Blob blob = _decodeBlob(p, end);
1432  p = blob.p;
1433  end = blob.end;
1434 
1435  if (p >= end)
1436  throw Exception("Decode Error: premature end of UID blob");
1437 
1438  const ID id = (ID) _popIntBlob<size_t>(p, end);
1439  const size_t size = _popIntBlob<size_t>(p, end);
1440 
1441  const UID uid = { id, size };
1442  return uid;
1443  }
1444 
1445  static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1446  _Blob blob = _decodeBlob(p, end);
1447  p = blob.p;
1448  end = blob.end;
1449 
1450  UIDChain chain;
1451  while (p < end) {
1452  const UID uid = _popUIDBlob(p, end);
1453  chain.push_back(uid);
1454  }
1455  assert(!chain.empty());
1456  return chain;
1457  }
1458 
1459  static Member _popMemberBlob(const char*& p, const char* end) {
1460  _Blob blob = _decodeBlob(p, end, false);
1461  p = blob.p;
1462  end = blob.end;
1463 
1464  Member m;
1465  if (p >= end) return m;
1466 
1467  m.m_uid = _popUIDBlob(p, end);
1468  m.m_offset = _popIntBlob<size_t>(p, end);
1469  m.m_name = _popStringBlob(p, end);
1470  m.m_type = _popDataTypeBlob(p, end);
1471  assert(m.type());
1472  assert(!m.name().empty());
1473  assert(m.uid().isValid());
1474  return m;
1475  }
1476 
1477  static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1478  _Blob blob = _decodeBlob(p, end, false);
1479  p = blob.p;
1480  end = blob.end;
1481 
1482  std::vector<Member> members;
1483  while (p < end) {
1484  const Member member = _popMemberBlob(p, end);
1485  if (member)
1486  members.push_back(member);
1487  else
1488  break;
1489  }
1490  return members;
1491  }
1492 
1493  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1494  const DataType& type = obj.type();
1495  if (type.isPrimitive() && !type.isPointer()) {
1496  obj.m_data.resize(type.size());
1497  if (type.isInteger() || type.isEnum()) {
1498  if (type.isSigned()) {
1499  if (type.size() == 1)
1500  _popIntBlob<int8_t>(p, end, obj.m_data);
1501  else if (type.size() == 2)
1502  _popIntBlob<int16_t>(p, end, obj.m_data);
1503  else if (type.size() == 4)
1504  _popIntBlob<int32_t>(p, end, obj.m_data);
1505  else if (type.size() == 8)
1506  _popIntBlob<int64_t>(p, end, obj.m_data);
1507  else
1508  assert(false /* unknown signed int type size */);
1509  } else {
1510  if (type.size() == 1)
1511  _popIntBlob<uint8_t>(p, end, obj.m_data);
1512  else if (type.size() == 2)
1513  _popIntBlob<uint16_t>(p, end, obj.m_data);
1514  else if (type.size() == 4)
1515  _popIntBlob<uint32_t>(p, end, obj.m_data);
1516  else if (type.size() == 8)
1517  _popIntBlob<uint64_t>(p, end, obj.m_data);
1518  else
1519  assert(false /* unknown unsigned int type size */);
1520  }
1521  } else if (type.isReal()) {
1522  if (type.size() == sizeof(float))
1523  _popRealBlob<float>(p, end, obj.m_data);
1524  else if (type.size() == sizeof(double))
1525  _popRealBlob<double>(p, end, obj.m_data);
1526  else
1527  assert(false /* unknown floating point type */);
1528  } else if (type.isBool()) {
1529  _popIntBlob<uint8_t>(p, end, obj.m_data);
1530  } else {
1531  assert(false /* unknown primitive type */);
1532  }
1533 
1534  } else {
1535  // don't whine if the empty blob was not added on encoder side
1536  _Blob blob = _decodeBlob(p, end, false);
1537  p = blob.p;
1538  end = blob.end;
1539  }
1540  }
1541 
1542  static Object _popObjectBlob(const char*& p, const char* end) {
1543  _Blob blob = _decodeBlob(p, end, false);
1544  p = blob.p;
1545  end = blob.end;
1546 
1547  Object obj;
1548  if (p >= end) return obj;
1549 
1550  obj.m_type = _popDataTypeBlob(p, end);
1551  obj.m_version = _popIntBlob<Version>(p, end);
1552  obj.m_minVersion = _popIntBlob<Version>(p, end);
1553  obj.m_uid = _popUIDChainBlob(p, end);
1554  obj.m_members = _popMembersBlob(p, end);
1555  _popPrimitiveValue(p, end, obj);
1556  assert(obj.type());
1557  return obj;
1558  }
1559 
1560  void Archive::_popObjectsBlob(const char*& p, const char* end) {
1561  _Blob blob = _decodeBlob(p, end, false);
1562  p = blob.p;
1563  end = blob.end;
1564 
1565  if (p >= end)
1566  throw Exception("Decode Error: Premature end of objects blob");
1567 
1568  while (true) {
1569  const Object obj = _popObjectBlob(p, end);
1570  if (!obj) break;
1571  m_allObjects[obj.uid()] = obj;
1572  }
1573  }
1574 
1575  void Archive::_popRootBlob(const char*& p, const char* end) {
1576  _Blob blob = _decodeBlob(p, end, false);
1577  p = blob.p;
1578  end = blob.end;
1579 
1580  if (p >= end)
1581  throw Exception("Decode Error: Premature end of root blob");
1582 
1583  // just in case this encoding format will be extended in future
1584  // (currently not used)
1585  const int formatMinorVersion = _popIntBlob<int>(p, end);
1586 
1587  m_root = _popUIDBlob(p, end);
1588  if (!m_root)
1589  throw Exception("Decode Error: No root object");
1590 
1591  _popObjectsBlob(p, end);
1592  if (!m_allObjects[m_root])
1593  throw Exception("Decode Error: Missing declared root object");
1594 
1595  m_name = _popStringBlob(p, end);
1596  m_comment = _popStringBlob(p, end);
1597  m_timeCreated = _popTimeBlob(p, end);
1598  m_timeModified = _popTimeBlob(p, end);
1599  }
1600 
1616  void Archive::decode(const RawData& data) {
1617  m_rawData = data;
1618  m_allObjects.clear();
1619  m_isModified = false;
1620  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1621  const char* p = (const char*) &data[0];
1622  const char* end = p + data.size();
1623  if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1624  throw Exception("Decode Error: Magic start missing!");
1625  p += strlen(MAGIC_START);
1626  _popRootBlob(p, end);
1627  }
1628 
1649  void Archive::decode(const uint8_t* data, size_t size) {
1650  RawData rawData;
1651  rawData.resize(size);
1652  memcpy(&rawData[0], data, size);
1653  decode(rawData);
1654  }
1655 
1672  if (m_isModified) encode();
1673  return m_rawData;
1674  }
1675 
1681  String Archive::rawDataFormat() const {
1682  return MAGIC_START;
1683  }
1684 
1699  bool Archive::isModified() const {
1700  return m_isModified;
1701  }
1702 
1709  m_allObjects.clear();
1710  m_operation = OPERATION_NONE;
1711  m_root = NO_UID;
1712  m_rawData.clear();
1713  m_isModified = false;
1714  m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1715  }
1716 
1724  String Archive::name() const {
1725  return m_name;
1726  }
1727 
1737  void Archive::setName(String name) {
1738  if (m_name == name) return;
1739  m_name = name;
1740  m_isModified = true;
1741  }
1742 
1750  String Archive::comment() const {
1751  return m_comment;
1752  }
1753 
1763  void Archive::setComment(String comment) {
1764  if (m_comment == comment) return;
1765  m_comment = comment;
1766  m_isModified = true;
1767  }
1768 
1769  static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1770  tm* pTm;
1771  switch (base) {
1772  case LOCAL_TIME:
1773  pTm = localtime(&time);
1774  break;
1775  case UTC_TIME:
1776  pTm = gmtime(&time);
1777  break;
1778  default:
1779  throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1780  }
1781  if (!pTm)
1782  throw Exception("Failed assembling time stamp structure");
1783  return *pTm;
1784  }
1785 
1791  time_t Archive::timeStampCreated() const {
1792  return m_timeCreated;
1793  }
1794 
1801  return m_timeModified;
1802  }
1803 
1815  return _convertTimeStamp(m_timeCreated, base);
1816  }
1817 
1829  return _convertTimeStamp(m_timeModified, base);
1830  }
1831 
1849  void Archive::removeMember(Object& parent, const Member& member) {
1850  parent.remove(member);
1851  m_isModified = true;
1852  }
1853 
1869  void Archive::remove(const Object& obj) {
1870  //FIXME: Should traverse from root object and remove all members associated with this object
1871  if (!obj.uid()) return;
1872  m_allObjects.erase(obj.uid());
1873  m_isModified = true;
1874  }
1875 
1888  return m_allObjects[uid];
1889  }
1890 
1902  if (!object) return;
1903  object.setVersion(v);
1904  m_isModified = true;
1905  }
1906 
1918  if (!object) return;
1919  object.setMinVersion(v);
1920  m_isModified = true;
1921  }
1922 
1931  void Archive::setEnumValue(Object& object, uint64_t value) {
1932  if (!object) return;
1933  if (!object.type().isEnum())
1934  throw Exception("Not an enum data type");
1935  Object* pObject = &object;
1936  if (object.type().isPointer()) {
1937  Object& obj = objectByUID(object.uid(1));
1938  if (!obj) return;
1939  pObject = &obj;
1940  }
1941  const int nativeEnumSize = sizeof(enum operation_t);
1942  DataType& type = const_cast<DataType&>( pObject->type() );
1943  // original serializer ("sender") might have had a different word size
1944  // than this machine, adjust type object in this case
1945  if (type.size() != nativeEnumSize) {
1946  type.m_size = nativeEnumSize;
1947  }
1948  pObject->m_data.resize(type.size());
1949  void* ptr = &pObject->m_data[0];
1950  if (type.size() == 1)
1951  *(uint8_t*)ptr = (uint8_t)value;
1952  else if (type.size() == 2)
1953  *(uint16_t*)ptr = (uint16_t)value;
1954  else if (type.size() == 4)
1955  *(uint32_t*)ptr = (uint32_t)value;
1956  else if (type.size() == 8)
1957  *(uint64_t*)ptr = (uint64_t)value;
1958  else
1959  assert(false /* unknown enum type size */);
1960  m_isModified = true;
1961  }
1962 
1973  void Archive::setIntValue(Object& object, int64_t value) {
1974  if (!object) return;
1975  if (!object.type().isInteger())
1976  throw Exception("Not an integer data type");
1977  Object* pObject = &object;
1978  if (object.type().isPointer()) {
1979  Object& obj = objectByUID(object.uid(1));
1980  if (!obj) return;
1981  pObject = &obj;
1982  }
1983  const DataType& type = pObject->type();
1984  pObject->m_data.resize(type.size());
1985  void* ptr = &pObject->m_data[0];
1986  if (type.isSigned()) {
1987  if (type.size() == 1)
1988  *(int8_t*)ptr = (int8_t)value;
1989  else if (type.size() == 2)
1990  *(int16_t*)ptr = (int16_t)value;
1991  else if (type.size() == 4)
1992  *(int32_t*)ptr = (int32_t)value;
1993  else if (type.size() == 8)
1994  *(int64_t*)ptr = (int64_t)value;
1995  else
1996  assert(false /* unknown signed int type size */);
1997  } else {
1998  if (type.size() == 1)
1999  *(uint8_t*)ptr = (uint8_t)value;
2000  else if (type.size() == 2)
2001  *(uint16_t*)ptr = (uint16_t)value;
2002  else if (type.size() == 4)
2003  *(uint32_t*)ptr = (uint32_t)value;
2004  else if (type.size() == 8)
2005  *(uint64_t*)ptr = (uint64_t)value;
2006  else
2007  assert(false /* unknown unsigned int type size */);
2008  }
2009  m_isModified = true;
2010  }
2011 
2023  void Archive::setRealValue(Object& object, double value) {
2024  if (!object) return;
2025  if (!object.type().isReal())
2026  throw Exception("Not a real data type");
2027  Object* pObject = &object;
2028  if (object.type().isPointer()) {
2029  Object& obj = objectByUID(object.uid(1));
2030  if (!obj) return;
2031  pObject = &obj;
2032  }
2033  const DataType& type = pObject->type();
2034  pObject->m_data.resize(type.size());
2035  void* ptr = &pObject->m_data[0];
2036  if (type.size() == sizeof(float))
2037  *(float*)ptr = (float)value;
2038  else if (type.size() == sizeof(double))
2039  *(double*)ptr = (double)value;
2040  else
2041  assert(false /* unknown real type size */);
2042  m_isModified = true;
2043  }
2044 
2053  void Archive::setBoolValue(Object& object, bool value) {
2054  if (!object) return;
2055  if (!object.type().isBool())
2056  throw Exception("Not a bool data type");
2057  Object* pObject = &object;
2058  if (object.type().isPointer()) {
2059  Object& obj = objectByUID(object.uid(1));
2060  if (!obj) return;
2061  pObject = &obj;
2062  }
2063  const DataType& type = pObject->type();
2064  pObject->m_data.resize(type.size());
2065  bool* ptr = (bool*)&pObject->m_data[0];
2066  *ptr = value;
2067  m_isModified = true;
2068  }
2069 
2083  void Archive::setAutoValue(Object& object, String value) {
2084  if (!object) return;
2085  const DataType& type = object.type();
2086  if (type.isInteger())
2087  setIntValue(object, atoll(value.c_str()));
2088  else if (type.isReal())
2089  setRealValue(object, atof(value.c_str()));
2090  else if (type.isBool()) {
2091  String val = toLowerCase(value);
2092  if (val == "true" || val == "yes" || val == "1")
2093  setBoolValue(object, true);
2094  else if (val == "false" || val == "no" || val == "0")
2095  setBoolValue(object, false);
2096  else
2097  setBoolValue(object, atof(value.c_str()));
2098  } else if (type.isEnum())
2099  setEnumValue(object, atoll(value.c_str()));
2100  else
2101  throw Exception("Not a primitive data type");
2102  }
2103 
2113  String Archive::valueAsString(const Object& object) {
2114  if (!object)
2115  throw Exception("Invalid object");
2116  if (object.type().isClass())
2117  throw Exception("Object is class type");
2118  const Object* pObject = &object;
2119  if (object.type().isPointer()) {
2120  const Object& obj = objectByUID(object.uid(1));
2121  if (!obj) return "";
2122  pObject = &obj;
2123  }
2124  return _primitiveObjectValueToString(*pObject);
2125  }
2126 
2136  int64_t Archive::valueAsInt(const Object& object) {
2137  if (!object)
2138  throw Exception("Invalid object");
2139  if (!object.type().isInteger() && !object.type().isEnum())
2140  throw Exception("Object is neither an integer nor an enum");
2141  const Object* pObject = &object;
2142  if (object.type().isPointer()) {
2143  const Object& obj = objectByUID(object.uid(1));
2144  if (!obj) return 0;
2145  pObject = &obj;
2146  }
2147  return _primitiveObjectValueToNumber<int64_t>(*pObject);
2148  }
2149 
2159  double Archive::valueAsReal(const Object& object) {
2160  if (!object)
2161  throw Exception("Invalid object");
2162  if (!object.type().isReal())
2163  throw Exception("Object is not an real type");
2164  const Object* pObject = &object;
2165  if (object.type().isPointer()) {
2166  const Object& obj = objectByUID(object.uid(1));
2167  if (!obj) return 0;
2168  pObject = &obj;
2169  }
2170  return _primitiveObjectValueToNumber<double>(*pObject);
2171  }
2172 
2181  bool Archive::valueAsBool(const Object& object) {
2182  if (!object)
2183  throw Exception("Invalid object");
2184  if (!object.type().isBool())
2185  throw Exception("Object is not a bool");
2186  const Object* pObject = &object;
2187  if (object.type().isPointer()) {
2188  const Object& obj = objectByUID(object.uid(1));
2189  if (!obj) return 0;
2190  pObject = &obj;
2191  }
2192  return _primitiveObjectValueToNumber<bool>(*pObject);
2193  }
2194 
2195  // *************** Archive::Syncer ***************
2196  // *
2197 
2198  Archive::Syncer::Syncer(Archive& dst, Archive& src)
2199  : m_dst(dst), m_src(src)
2200  {
2201  const Object srcRootObj = src.rootObject();
2202  const Object dstRootObj = dst.rootObject();
2203  if (!srcRootObj)
2204  throw Exception("No source root object!");
2205  if (!dstRootObj)
2206  throw Exception("Expected destination root object not found!");
2207  syncObject(dstRootObj, srcRootObj);
2208  }
2209 
2210  void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2211  assert(srcObj.rawData().size() == dstObj.type().size());
2212  void* pDst = (void*)dstObj.uid().id;
2213  memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2214  }
2215 
2216  void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2217  assert(dstObj.type().isPointer());
2218  assert(dstObj.type() == srcObj.type());
2219  const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2220  const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2221  syncObject(pointedDstObject, pointedSrcObject);
2222  }
2223 
2224  void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2225  if (!dstObj || !srcObj) return; // end of recursion
2226  if (!dstObj.isVersionCompatibleTo(srcObj))
2227  throw Exception("Version incompatible (destination version " +
2228  ToString(dstObj.version()) + " [min. version " +
2229  ToString(dstObj.minVersion()) + "], source version " +
2230  ToString(srcObj.version()) + " [min. version " +
2231  ToString(srcObj.minVersion()) + "])");
2232  if (dstObj.type() != srcObj.type())
2233  throw Exception("Incompatible data structure type (destination type " +
2234  dstObj.type().asLongDescr() + " vs. source type " +
2235  srcObj.type().asLongDescr() + ")");
2236 
2237  // prevent syncing this object again, and thus also prevent endless
2238  // loop on data structures with cyclic relations
2239  m_dst.m_allObjects.erase(dstObj.uid());
2240 
2241  if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2242  syncPrimitive(dstObj, srcObj);
2243  return; // end of recursion
2244  }
2245 
2246  if (dstObj.type().isPointer()) {
2247  syncPointer(dstObj, srcObj);
2248  return;
2249  }
2250 
2251  assert(dstObj.type().isClass());
2252  for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2253  const Member& srcMember = srcObj.members()[iMember];
2254  Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2255  if (!dstMember)
2256  throw Exception("Expected member missing in destination object");
2257  syncMember(dstMember, srcMember);
2258  }
2259  }
2260 
2261  Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2262  Member dstMember = dstObj.memberNamed(srcMember.name());
2263  if (dstMember)
2264  return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2265  std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2266  if (members.size() <= 0)
2267  return Member();
2268  if (members.size() == 1)
2269  return members[0];
2270  for (int i = 0; i < members.size(); ++i)
2271  if (members[i].offset() == srcMember.offset())
2272  return members[i];
2273  const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2274  assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2275  for (int i = 0; i < members.size(); ++i) {
2276  const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2277  if (dstSeqNr == srcSeqNr)
2278  return members[i];
2279  }
2280  return Member(); // give up!
2281  }
2282 
2283  void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2284  assert(dstMember && srcMember);
2285  assert(dstMember.type() == srcMember.type());
2286  const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2287  const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2288  syncObject(dstObj, srcObj);
2289  }
2290 
2291  // *************** Exception ***************
2292  // *
2293 
2294  Exception::Exception() {
2295  }
2296 
2297  Exception::Exception(String format, ...) {
2298  va_list arg;
2299  va_start(arg, format);
2300  Message = assemble(format, arg);
2301  va_end(arg);
2302  }
2303 
2304  Exception::Exception(String format, va_list arg) {
2305  Message = assemble(format, arg);
2306  }
2307 
2314  std::cout << "Serialization::Exception: " << Message << std::endl;
2315  }
2316 
2317  String Exception::assemble(String format, va_list arg) {
2318  char* buf = NULL;
2319  vasprintf(&buf, format.c_str(), arg);
2320  String s = buf;
2321  free(buf);
2322  return s;
2323  }
2324 
2325 } // 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&#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.