libgig 4.4.1
Serialization.cpp
1/***************************************************************************
2 * *
3 * Copyright (C) 2017-2020 Christian Schoenebeck *
4 * <cuse@users.sourceforge.net> *
5 * *
6 * This library is part of libgig. *
7 * *
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24// enable implementation specific declarations in Serialization.h required to
25// build this C++ unit, which should be ignored in the public API though
26#define LIBGIG_SERIALIZATION_INTERNAL 1
27
28#include "Serialization.h"
29
30#include <iostream>
31#include <string.h> // for memcpy()
32#include <stdlib.h> // for atof()
33#ifdef _MSC_VER
34# include <windows.h>
35# include <dbghelp.h>
36#else
37# include <cxxabi.h>
38#endif
39#include "helper.h"
40
41#define LIBGIG_EPOCH_TIME ((time_t)0)
42
43namespace Serialization {
44
45 // *************** DataType ***************
46 // *
47
48 static UID _createNullUID() {
49 const UID uid = { NULL, 0 };
50 return uid;
51 }
52
53 const UID NO_UID = _createNullUID();
54
66 bool UID::isValid() const {
67 return id != NULL && id != (void*)-1 && size;
68 }
69
70 // *************** DataType ***************
71 // *
72
83 m_size = 0;
84 m_isPointer = false;
85 }
86
114 DataType::DataType(bool isPointer, int size, String baseType,
115 String customType1, String customType2)
116 {
117 m_size = size;
118 m_isPointer = isPointer;
119 m_baseTypeName = baseType;
120 m_customTypeName = customType1;
121 m_customTypeName2 = customType2;
122 }
123
134 bool DataType::isValid() const {
135 return m_size;
136 }
137
143 bool DataType::isPointer() const {
144 return m_isPointer;
145 }
146
172 bool DataType::isClass() const {
173 return m_baseTypeName == "class";
174 }
175
197 return !isClass() && !isArray() && !isSet() && !isMap();
198 }
199
210 bool DataType::isString() const {
211 return m_baseTypeName == "String";
212 }
213
228 bool DataType::isInteger() const {
229 return m_baseTypeName.substr(0, 3) == "int" ||
230 m_baseTypeName.substr(0, 4) == "uint";
231 }
232
245 bool DataType::isReal() const {
246 return m_baseTypeName.substr(0, 4) == "real";
247 }
248
260 bool DataType::isBool() const {
261 return m_baseTypeName == "bool";
262 }
263
275 bool DataType::isEnum() const {
276 return m_baseTypeName == "enum";
277 }
278
291 bool DataType::isArray() const {
292 return m_baseTypeName == "Array";
293 }
294
307 bool DataType::isSet() const {
308 return m_baseTypeName == "Set";
309 }
310
323 bool DataType::isMap() const {
324 return m_baseTypeName == "Map";
325 }
326
340 bool DataType::isSigned() const {
341 return m_baseTypeName.substr(0, 3) == "int" ||
342 isReal();
343 }
344
363 bool DataType::operator==(const DataType& other) const {
364 return m_baseTypeName == other.m_baseTypeName &&
365 m_customTypeName == other.m_customTypeName &&
366 m_customTypeName2 == other.m_customTypeName2 &&
367 (m_size == other.m_size || (isClass() && other.isClass())) &&
368 m_isPointer == other.m_isPointer;
369 }
370
376 bool DataType::operator!=(const DataType& other) const {
377 return !operator==(other);
378 }
379
391 bool DataType::operator<(const DataType& other) const {
392 return m_baseTypeName < other.m_baseTypeName ||
393 (m_baseTypeName == other.m_baseTypeName &&
394 (m_customTypeName < other.m_customTypeName ||
395 (m_customTypeName == other.m_customTypeName &&
396 (m_customTypeName2 < other.m_customTypeName2 ||
397 (m_customTypeName2 == other.m_customTypeName2 &&
398 (m_size < other.m_size ||
399 (m_size == other.m_size &&
400 m_isPointer < other.m_isPointer)))))));
401 }
402
414 bool DataType::operator>(const DataType& other) const {
415 return !(operator==(other) || operator<(other));
416 }
417
433 String s = m_baseTypeName;
434 if (!m_customTypeName.empty())
435 s += " " + customTypeName(true);
436 if (!m_customTypeName2.empty())
437 s += " " + customTypeName2(true);
438 if (isPointer())
439 s += " pointer";
440 return s;
441 }
442
473 return m_baseTypeName;
474 }
475
476 static String _demangleTypeName(const char* name) {
477#ifdef _MSC_VER
478 const size_t MAXLENGTH = 1024;
479 char result[MAXLENGTH];
480
481 //FIXME: calling UnDecorateSymbolName() is not thread safe!
482 //Skip the first char
483 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
484 if (size)
485 {
486 return result;
487 }
488 return name;
489#else
490 int status;
491 char* result =
492 abi::__cxa_demangle(name, 0, 0, &status);
493 String sResult = result;
494 free(result);
495 return (status == 0) ? sResult : name;
496#endif
497 }
498
535 String DataType::customTypeName(bool demangle) const {
536 if (!demangle) return m_customTypeName;
537 return _demangleTypeName(m_customTypeName.c_str());
538 }
539
547 String DataType::customTypeName2(bool demangle) const {
548 if (!demangle) return m_customTypeName2;
549 return _demangleTypeName(m_customTypeName2.c_str());
550 }
551
552 // *************** Member ***************
553 // *
554
568 m_uid = NO_UID;
569 m_offset = 0;
570 }
571
572 Member::Member(String name, UID uid, ssize_t offset, DataType type) {
573 m_name = name;
574 m_uid = uid;
575 m_offset = offset;
576 m_type = type;
577 }
578
593 UID Member::uid() const {
594 return m_uid;
595 }
596
618 return m_name;
619 }
620
662 ssize_t Member::offset() const {
663 return m_offset;
664 }
665
670 const DataType& Member::type() const {
671 return m_type;
672 }
673
684 bool Member::isValid() const {
685 return m_uid && !m_name.empty() && m_type;
686 }
687
696 bool Member::operator==(const Member& other) const {
697 return m_uid == other.m_uid &&
698 m_offset == other.m_offset &&
699 m_name == other.m_name &&
700 m_type == other.m_type;
701 }
702
708 bool Member::operator!=(const Member& other) const {
709 return !operator==(other);
710 }
711
724 bool Member::operator<(const Member& other) const {
725 return m_uid < other.m_uid ||
726 (m_uid == other.m_uid &&
727 (m_offset < other.m_offset ||
728 (m_offset == other.m_offset &&
729 (m_name < other.m_name ||
730 (m_name == other.m_name &&
731 m_type < other.m_type)))));
732 }
733
746 bool Member::operator>(const Member& other) const {
747 return !(operator==(other) || operator<(other));
748 }
749
750 // *************** Object ***************
751 // *
752
765 m_version = 0;
766 m_minVersion = 0;
767 }
768
787 m_type = type;
788 m_uid = uidChain;
789 m_version = 0;
790 m_minVersion = 0;
791 //m_data.resize(type.size());
792 }
793
804 bool Object::isValid() const {
805 return m_type && !m_uid.empty();
806 }
807
819 UID Object::uid(int index) const {
820 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
821 }
822
823 static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
824 if (type.isPrimitive() && !type.isPointer()) {
825 if (type.isInteger() || type.isEnum()) {
826 if (type.isSigned()) {
827 if (type.size() == 1)
828 *(int8_t*)ptr = (int8_t) atoll(s);
829 else if (type.size() == 2)
830 *(int16_t*)ptr = (int16_t) atoll(s);
831 else if (type.size() == 4)
832 *(int32_t*)ptr = (int32_t) atoll(s);
833 else if (type.size() == 8)
834 *(int64_t*)ptr = (int64_t) atoll(s);
835 else
836 assert(false /* unknown signed int type size */);
837 } else {
838 if (type.size() == 1)
839 *(uint8_t*)ptr = (uint8_t) atoll(s);
840 else if (type.size() == 2)
841 *(uint16_t*)ptr = (uint16_t) atoll(s);
842 else if (type.size() == 4)
843 *(uint32_t*)ptr = (uint32_t) atoll(s);
844 else if (type.size() == 8)
845 *(uint64_t*)ptr = (uint64_t) atoll(s);
846 else
847 assert(false /* unknown unsigned int type size */);
848 }
849 } else if (type.isReal()) {
850 if (type.size() == sizeof(float))
851 *(float*)ptr = (float) atof(s);
852 else if (type.size() == sizeof(double))
853 *(double*)ptr = (double) atof(s);
854 else
855 assert(false /* unknown floating point type */);
856 } else if (type.isBool()) {
857 String lower = toLowerCase(s);
858 const bool b = lower != "0" && lower != "false" && lower != "no";
859 *(bool*)ptr = b;
860 } else if (type.isString()) {
861 *(String*)ptr = s;
862 } else {
863 assert(false /* no built-in cast from string support for this data type */);
864 }
865 }
866 }
867
884 const ID& id = uid().id;
885 void* ptr = (void*)id;
886 _setNativeValueFromString(ptr, m_type, s.c_str());
887 }
888
895 const UIDChain& Object::uidChain() const {
896 return m_uid;
897 }
898
904 const DataType& Object::type() const {
905 return m_type;
906 }
907
930 const RawData& Object::rawData() const {
931 return m_data;
932 }
933
945 return m_version;
946 }
947
960 return m_minVersion;
961 }
962
995 std::vector<Member>& Object::members() {
996 return m_members;
997 }
998
1005 const std::vector<Member>& Object::members() const {
1006 return m_members;
1007 }
1008
1019 bool Object::operator==(const Object& other) const {
1020 // ignoring all other member variables here
1021 // (since UID stands for "unique" ;-) )
1022 return m_uid == other.m_uid &&
1023 m_type == other.m_type;
1024 }
1025
1031 bool Object::operator!=(const Object& other) const {
1032 return !operator==(other);
1033 }
1034
1047 bool Object::operator<(const Object& other) const {
1048 // ignoring all other member variables here
1049 // (since UID stands for "unique" ;-) )
1050 return m_uid < other.m_uid ||
1051 (m_uid == other.m_uid &&
1052 m_type < other.m_type);
1053 }
1054
1067 bool Object::operator>(const Object& other) const {
1068 return !(operator==(other) || operator<(other));
1069 }
1070
1089 bool Object::isVersionCompatibleTo(const Object& other) const {
1090 if (this->version() == other.version())
1091 return true;
1092 if (this->version() > other.version())
1093 return this->minVersion() <= other.version();
1094 else
1095 return other.minVersion() <= this->version();
1096 }
1097
1098 void Object::setVersion(Version v) {
1099 m_version = v;
1100 }
1101
1102 void Object::setMinVersion(Version v) {
1103 m_minVersion = v;
1104 }
1105
1136 for (int i = 0; i < m_members.size(); ++i)
1137 if (m_members[i].name() == name)
1138 return m_members[i];
1139 return Member();
1140 }
1141
1156 Member Object::memberByUID(const UID& uid) const {
1157 if (!uid) return Member();
1158 for (int i = 0; i < m_members.size(); ++i)
1159 if (m_members[i].uid() == uid)
1160 return m_members[i];
1161 return Member();
1162 }
1163
1164 void Object::remove(const Member& member) {
1165 for (int i = 0; i < m_members.size(); ++i) {
1166 if (m_members[i] == member) {
1167 m_members.erase(m_members.begin() + i);
1168 return;
1169 }
1170 }
1171 }
1172
1188 std::vector<Member> Object::membersOfType(const DataType& type) const {
1189 std::vector<Member> v;
1190 for (int i = 0; i < m_members.size(); ++i) {
1191 const Member& member = m_members[i];
1192 if (member.type() == type)
1193 v.push_back(member);
1194 }
1195 return v;
1196 }
1197
1229 int Object::sequenceIndexOf(const Member& member) const {
1230 for (int i = 0; i < m_members.size(); ++i)
1231 if (m_members[i] == member)
1232 return i;
1233 return -1;
1234 }
1235
1236 // *************** Archive ***************
1237 // *
1238
1258 m_operation = OPERATION_NONE;
1259 m_root = NO_UID;
1260 m_isModified = false;
1261 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1262 }
1263
1280 m_operation = OPERATION_NONE;
1281 m_root = NO_UID;
1282 m_isModified = false;
1283 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1284 decode(data);
1285 }
1286
1307 Archive::Archive(const uint8_t* data, size_t size) {
1308 m_operation = OPERATION_NONE;
1309 m_root = NO_UID;
1310 m_isModified = false;
1311 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1312 decode(data, size);
1313 }
1314
1315 Archive::~Archive() {
1316 }
1317
1329 return m_allObjects[m_root];
1330 }
1331
1332 static String _encodeBlob(String data) {
1333 return ToString(data.length()) + ":" + data;
1334 }
1335
1336 static String _encode(const UID& uid) {
1337 String s;
1338 s += _encodeBlob(ToString(size_t(uid.id)));
1339 s += _encodeBlob(ToString(size_t(uid.size)));
1340 return _encodeBlob(s);
1341 }
1342
1343 static String _encode(const time_t& time) {
1344 return _encodeBlob(ToString(time));
1345 }
1346
1347 static String _encode(const DataType& type) {
1348 String s;
1349
1350 // Srx v1.0 format (mandatory):
1351 s += _encodeBlob(type.baseTypeName());
1352 s += _encodeBlob(type.customTypeName());
1353 s += _encodeBlob(ToString(type.size()));
1354 s += _encodeBlob(ToString(type.isPointer()));
1355
1356 // Srx v1.1 format:
1357 s += _encodeBlob(type.customTypeName2());
1358
1359 return _encodeBlob(s);
1360 }
1361
1362 static String _encode(const UIDChain& chain) {
1363 String s;
1364 for (int i = 0; i < chain.size(); ++i)
1365 s += _encode(chain[i]);
1366 return _encodeBlob(s);
1367 }
1368
1369 static String _encode(const Member& member) {
1370 String s;
1371 s += _encode(member.uid());
1372 s += _encodeBlob(ToString(member.offset()));
1373 s += _encodeBlob(member.name());
1374 s += _encode(member.type());
1375 return _encodeBlob(s);
1376 }
1377
1378 static String _encode(const std::vector<Member>& members) {
1379 String s;
1380 for (int i = 0; i < members.size(); ++i)
1381 s += _encode(members[i]);
1382 return _encodeBlob(s);
1383 }
1384
1385 static String _primitiveObjectValueToString(const Object& obj) {
1386 String s;
1387 const DataType& type = obj.type();
1388 const ID& id = obj.uid().id;
1389 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1390 if (!obj.m_data.empty())
1391 assert(type.size() == obj.m_data.size());
1392 if (type.isPrimitive() && !type.isPointer()) {
1393 if (type.isInteger() || type.isEnum()) {
1394 if (type.isSigned()) {
1395 if (type.size() == 1)
1396 s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1397 else if (type.size() == 2)
1398 s = ToString(*(int16_t*)ptr);
1399 else if (type.size() == 4)
1400 s = ToString(*(int32_t*)ptr);
1401 else if (type.size() == 8)
1402 s = ToString(*(int64_t*)ptr);
1403 else
1404 assert(false /* unknown signed int type size */);
1405 } else {
1406 if (type.size() == 1)
1407 s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1408 else if (type.size() == 2)
1409 s = ToString(*(uint16_t*)ptr);
1410 else if (type.size() == 4)
1411 s = ToString(*(uint32_t*)ptr);
1412 else if (type.size() == 8)
1413 s = ToString(*(uint64_t*)ptr);
1414 else
1415 assert(false /* unknown unsigned int type size */);
1416 }
1417 } else if (type.isReal()) {
1418 if (type.size() == sizeof(float))
1419 s = ToString(*(float*)ptr);
1420 else if (type.size() == sizeof(double))
1421 s = ToString(*(double*)ptr);
1422 else
1423 assert(false /* unknown floating point type */);
1424 } else if (type.isBool()) {
1425 s = ToString(*(bool*)ptr);
1426 } else if (type.isString()) {
1427 s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1428 } else {
1429 assert(false /* unknown primitive type */);
1430 }
1431 }
1432 return s;
1433 }
1434
1435 template<typename T>
1436 inline T _stringToNumber(const String& s) {
1437 assert(false /* String cast to unknown primitive number type */);
1438 }
1439
1440 template<>
1441 inline int64_t _stringToNumber(const String& s) {
1442 return atoll(s.c_str());
1443 }
1444
1445 template<>
1446 inline double _stringToNumber(const String& s) {
1447 return atof(s.c_str());
1448 }
1449
1450 template<>
1451 inline bool _stringToNumber(const String& s) {
1452 return (bool) atoll(s.c_str());
1453 }
1454
1455 template<typename T>
1456 static T _primitiveObjectValueToNumber(const Object& obj) {
1457 T value = 0;
1458 const DataType& type = obj.type();
1459 const ID& id = obj.uid().id;
1460 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1461 if (!obj.m_data.empty())
1462 assert(type.size() == obj.m_data.size());
1463 if (type.isPrimitive() && !type.isPointer()) {
1464 if (type.isInteger() || type.isEnum()) {
1465 if (type.isSigned()) {
1466 if (type.size() == 1)
1467 value = (T)*(int8_t*)ptr;
1468 else if (type.size() == 2)
1469 value = (T)*(int16_t*)ptr;
1470 else if (type.size() == 4)
1471 value = (T)*(int32_t*)ptr;
1472 else if (type.size() == 8)
1473 value = (T)*(int64_t*)ptr;
1474 else
1475 assert(false /* unknown signed int type size */);
1476 } else {
1477 if (type.size() == 1)
1478 value = (T)*(uint8_t*)ptr;
1479 else if (type.size() == 2)
1480 value = (T)*(uint16_t*)ptr;
1481 else if (type.size() == 4)
1482 value = (T)*(uint32_t*)ptr;
1483 else if (type.size() == 8)
1484 value = (T)*(uint64_t*)ptr;
1485 else
1486 assert(false /* unknown unsigned int type size */);
1487 }
1488 } else if (type.isReal()) {
1489 if (type.size() == sizeof(float))
1490 value = (T)*(float*)ptr;
1491 else if (type.size() == sizeof(double))
1492 value = (T)*(double*)ptr;
1493 else
1494 assert(false /* unknown floating point type */);
1495 } else if (type.isBool()) {
1496 value = (T)*(bool*)ptr;
1497 } else if (type.isString()) {
1498 value = _stringToNumber<T>(
1499 obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1500 );
1501 } else {
1502 assert(false /* unknown primitive type */);
1503 }
1504 }
1505 return value;
1506 }
1507
1508 static String _encodePrimitiveValue(const Object& obj) {
1509 return _encodeBlob( _primitiveObjectValueToString(obj) );
1510 }
1511
1512 static String _encode(const Object& obj) {
1513 String s;
1514 s += _encode(obj.type());
1515 s += _encodeBlob(ToString(obj.version()));
1516 s += _encodeBlob(ToString(obj.minVersion()));
1517 s += _encode(obj.uidChain());
1518 s += _encode(obj.members());
1519 s += _encodePrimitiveValue(obj);
1520 return _encodeBlob(s);
1521 }
1522
1523 String _encode(const Archive::ObjectPool& objects) {
1524 String s;
1525 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1526 itObject != objects.end(); ++itObject)
1527 {
1528 const Object& obj = itObject->second;
1529 s += _encode(obj);
1530 }
1531 return _encodeBlob(s);
1532 }
1533
1534 /*
1535 * Srx format history:
1536 * - 1.0: Initial version.
1537 * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1538 * 2nd custom type name (e.g. "Map" types which always contain two
1539 * user defined types).
1540 */
1541 #define MAGIC_START "Srx1v"
1542 #define ENCODING_FORMAT_MINOR_VERSION 1
1543
1544 String Archive::_encodeRootBlob() {
1545 String s;
1546 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1547 s += _encode(m_root);
1548 s += _encode(m_allObjects);
1549 s += _encodeBlob(m_name);
1550 s += _encodeBlob(m_comment);
1551 s += _encode(m_timeCreated);
1552 s += _encode(m_timeModified);
1553 return _encodeBlob(s);
1554 }
1555
1556 void Archive::encode() {
1557 m_rawData.clear();
1558 String s = MAGIC_START;
1559 m_timeModified = time(NULL);
1560 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1561 m_timeCreated = m_timeModified;
1562 s += _encodeRootBlob();
1563 m_rawData.resize(s.length() + 1);
1564 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1565 m_isModified = false;
1566 }
1567
1568 struct _Blob {
1569 const char* p;
1570 const char* end;
1571 };
1572
1573 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1574 if (!bThrow && p >= end) {
1575 const _Blob blob = { p, end };
1576 return blob;
1577 }
1578 size_t sz = 0;
1579 for (; true; ++p) {
1580 if (p >= end)
1581 throw Exception("Decode Error: Missing blob");
1582 const char& c = *p;
1583 if (c == ':') break;
1584 if (c < '0' || c > '9')
1585 throw Exception("Decode Error: Missing blob size");
1586 sz *= 10;
1587 sz += size_t(c - '0');
1588 }
1589 ++p;
1590 if (p + sz > end)
1591 throw Exception("Decode Error: Premature end of blob");
1592 const _Blob blob = { p, p + sz };
1593 return blob;
1594 }
1595
1596 template<typename T_int>
1597 static T_int _popIntBlob(const char*& p, const char* end) {
1598 _Blob blob = _decodeBlob(p, end);
1599 p = blob.p;
1600 end = blob.end;
1601
1602 T_int sign = 1;
1603 T_int i = 0;
1604 if (p >= end)
1605 throw Exception("Decode Error: premature end of int blob");
1606 if (*p == '-') {
1607 sign = -1;
1608 ++p;
1609 }
1610 for (; p < end; ++p) {
1611 const char& c = *p;
1612 if (c < '0' || c > '9')
1613 throw Exception("Decode Error: Invalid int blob format");
1614 i *= 10;
1615 i += size_t(c - '0');
1616 }
1617 return i * sign;
1618 }
1619
1620 template<typename T_int>
1621 static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1622 const T_int i = _popIntBlob<T_int>(p, end);
1623 *(T_int*)&rawData[0] = i;
1624 }
1625
1626 template<typename T_real>
1627 static T_real _popRealBlob(const char*& p, const char* end) {
1628 _Blob blob = _decodeBlob(p, end);
1629 p = blob.p;
1630 end = blob.end;
1631
1632 if (p >= end || (end - p) < 1)
1633 throw Exception("Decode Error: premature end of real blob");
1634
1635 String s(p, size_t(end - p));
1636
1637 T_real r;
1638 if (sizeof(T_real) <= sizeof(double))
1639 r = atof(s.c_str());
1640 else
1641 assert(false /* unknown real type */);
1642
1643 p += s.length();
1644
1645 return r;
1646 }
1647
1648 template<typename T_real>
1649 static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1650 const T_real r = _popRealBlob<T_real>(p, end);
1651 *(T_real*)&rawData[0] = r;
1652 }
1653
1654 static String _popStringBlob(const char*& p, const char* end) {
1655 _Blob blob = _decodeBlob(p, end);
1656 p = blob.p;
1657 end = blob.end;
1658 if (end - p < 0)
1659 throw Exception("Decode Error: missing String blob");
1660 String s;
1661 const size_t sz = end - p;
1662 s.resize(sz);
1663 memcpy(&s[0], p, sz);
1664 p += sz;
1665 return s;
1666 }
1667
1668 static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1669 String s = _popStringBlob(p, end);
1670 rawData.resize(s.length() + 1);
1671 strcpy((char*)&rawData[0], &s[0]);
1672 }
1673
1674 static time_t _popTimeBlob(const char*& p, const char* end) {
1675 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1676 return (time_t) i;
1677 }
1678
1679 static DataType _popDataTypeBlob(const char*& p, const char* end) {
1680 _Blob blob = _decodeBlob(p, end);
1681 p = blob.p;
1682 end = blob.end;
1683
1684 DataType type;
1685
1686 // Srx v1.0 format (mandatory):
1687 type.m_baseTypeName = _popStringBlob(p, end);
1688 type.m_customTypeName = _popStringBlob(p, end);
1689 type.m_size = _popIntBlob<int>(p, end);
1690 type.m_isPointer = _popIntBlob<bool>(p, end);
1691
1692 // Srx v1.1 format (optional):
1693 if (p < end)
1694 type.m_customTypeName2 = _popStringBlob(p, end);
1695
1696 return type;
1697 }
1698
1699 static UID _popUIDBlob(const char*& p, const char* end) {
1700 _Blob blob = _decodeBlob(p, end);
1701 p = blob.p;
1702 end = blob.end;
1703
1704 if (p >= end)
1705 throw Exception("Decode Error: premature end of UID blob");
1706
1707 const ID id = (ID) _popIntBlob<size_t>(p, end);
1708 const size_t size = _popIntBlob<size_t>(p, end);
1709
1710 const UID uid = { id, size };
1711 return uid;
1712 }
1713
1714 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1715 _Blob blob = _decodeBlob(p, end);
1716 p = blob.p;
1717 end = blob.end;
1718
1719 UIDChain chain;
1720 while (p < end) {
1721 const UID uid = _popUIDBlob(p, end);
1722 chain.push_back(uid);
1723 }
1724 assert(!chain.empty());
1725 return chain;
1726 }
1727
1728 static Member _popMemberBlob(const char*& p, const char* end) {
1729 _Blob blob = _decodeBlob(p, end, false);
1730 p = blob.p;
1731 end = blob.end;
1732
1733 Member m;
1734 if (p >= end) return m;
1735
1736 m.m_uid = _popUIDBlob(p, end);
1737 m.m_offset = _popIntBlob<ssize_t>(p, end);
1738 m.m_name = _popStringBlob(p, end);
1739 m.m_type = _popDataTypeBlob(p, end);
1740 assert(m.type());
1741 assert(!m.name().empty());
1742 assert(m.uid().isValid());
1743 return m;
1744 }
1745
1746 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1747 _Blob blob = _decodeBlob(p, end, false);
1748 p = blob.p;
1749 end = blob.end;
1750
1751 std::vector<Member> members;
1752 while (p < end) {
1753 const Member member = _popMemberBlob(p, end);
1754 if (member)
1755 members.push_back(member);
1756 else
1757 break;
1758 }
1759 return members;
1760 }
1761
1762 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1763 const DataType& type = obj.type();
1764 if (type.isPrimitive() && !type.isPointer()) {
1765 obj.m_data.resize(type.size());
1766 if (type.isInteger() || type.isEnum()) {
1767 if (type.isSigned()) {
1768 if (type.size() == 1)
1769 _popIntBlob<int8_t>(p, end, obj.m_data);
1770 else if (type.size() == 2)
1771 _popIntBlob<int16_t>(p, end, obj.m_data);
1772 else if (type.size() == 4)
1773 _popIntBlob<int32_t>(p, end, obj.m_data);
1774 else if (type.size() == 8)
1775 _popIntBlob<int64_t>(p, end, obj.m_data);
1776 else
1777 assert(false /* unknown signed int type size */);
1778 } else {
1779 if (type.size() == 1)
1780 _popIntBlob<uint8_t>(p, end, obj.m_data);
1781 else if (type.size() == 2)
1782 _popIntBlob<uint16_t>(p, end, obj.m_data);
1783 else if (type.size() == 4)
1784 _popIntBlob<uint32_t>(p, end, obj.m_data);
1785 else if (type.size() == 8)
1786 _popIntBlob<uint64_t>(p, end, obj.m_data);
1787 else
1788 assert(false /* unknown unsigned int type size */);
1789 }
1790 } else if (type.isReal()) {
1791 if (type.size() == sizeof(float))
1792 _popRealBlob<float>(p, end, obj.m_data);
1793 else if (type.size() == sizeof(double))
1794 _popRealBlob<double>(p, end, obj.m_data);
1795 else
1796 assert(false /* unknown floating point type */);
1797 } else if (type.isBool()) {
1798 _popIntBlob<uint8_t>(p, end, obj.m_data);
1799 } else if (type.isString()) {
1800 _popStringBlob(p, end, obj.m_data);
1801 } else {
1802 assert(false /* unknown primitive type */);
1803 }
1804
1805 } else {
1806 // don't whine if the empty blob was not added on encoder side
1807 _Blob blob = _decodeBlob(p, end, false);
1808 p = blob.p;
1809 end = blob.end;
1810 }
1811 }
1812
1813 static Object _popObjectBlob(const char*& p, const char* end) {
1814 _Blob blob = _decodeBlob(p, end, false);
1815 p = blob.p;
1816 end = blob.end;
1817
1818 Object obj;
1819 if (p >= end) return obj;
1820
1821 obj.m_type = _popDataTypeBlob(p, end);
1822 obj.m_version = _popIntBlob<Version>(p, end);
1823 obj.m_minVersion = _popIntBlob<Version>(p, end);
1824 obj.m_uid = _popUIDChainBlob(p, end);
1825 obj.m_members = _popMembersBlob(p, end);
1826 _popPrimitiveValue(p, end, obj);
1827 assert(obj.type());
1828 return obj;
1829 }
1830
1831 void Archive::_popObjectsBlob(const char*& p, const char* end) {
1832 _Blob blob = _decodeBlob(p, end, false);
1833 p = blob.p;
1834 end = blob.end;
1835
1836 if (p >= end)
1837 throw Exception("Decode Error: Premature end of objects blob");
1838
1839 while (true) {
1840 const Object obj = _popObjectBlob(p, end);
1841 if (!obj) break;
1842 m_allObjects[obj.uid()] = obj;
1843 }
1844 }
1845
1846 void Archive::_popRootBlob(const char*& p, const char* end) {
1847 _Blob blob = _decodeBlob(p, end, false);
1848 p = blob.p;
1849 end = blob.end;
1850
1851 if (p >= end)
1852 throw Exception("Decode Error: Premature end of root blob");
1853
1854 // just in case this encoding format will be extended in future
1855 // (currently not used)
1856 const int formatMinorVersion = _popIntBlob<int>(p, end);
1857
1858 m_root = _popUIDBlob(p, end);
1859 if (!m_root)
1860 throw Exception("Decode Error: No root object");
1861
1862 _popObjectsBlob(p, end);
1863 if (!m_allObjects[m_root])
1864 throw Exception("Decode Error: Missing declared root object");
1865
1866 m_name = _popStringBlob(p, end);
1867 m_comment = _popStringBlob(p, end);
1868 m_timeCreated = _popTimeBlob(p, end);
1869 m_timeModified = _popTimeBlob(p, end);
1870 }
1871
1887 void Archive::decode(const RawData& data) {
1888 m_rawData = data;
1889 m_allObjects.clear();
1890 m_isModified = false;
1891 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1892 const char* p = (const char*) &data[0];
1893 const char* end = p + data.size();
1894 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1895 throw Exception("Decode Error: Magic start missing!");
1896 p += strlen(MAGIC_START);
1897 _popRootBlob(p, end);
1898 }
1899
1920 void Archive::decode(const uint8_t* data, size_t size) {
1922 rawData.resize(size);
1923 memcpy(&rawData[0], data, size);
1924 decode(rawData);
1925 }
1926
1943 if (m_isModified) encode();
1944 return m_rawData;
1945 }
1946
1953 return MAGIC_START;
1954 }
1955
1970 bool Archive::isModified() const {
1971 return m_isModified;
1972 }
1973
1980 m_allObjects.clear();
1981 m_operation = OPERATION_NONE;
1982 m_root = NO_UID;
1983 m_rawData.clear();
1984 m_isModified = false;
1985 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1986 }
1987
1996 return m_name;
1997 }
1998
2009 if (m_name == name) return;
2010 m_name = name;
2011 m_isModified = true;
2012 }
2013
2022 return m_comment;
2023 }
2024
2035 if (m_comment == comment) return;
2036 m_comment = comment;
2037 m_isModified = true;
2038 }
2039
2040 static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2041 tm* pTm;
2042 switch (base) {
2043 case LOCAL_TIME:
2044 pTm = localtime(&time);
2045 break;
2046 case UTC_TIME:
2047 pTm = gmtime(&time);
2048 break;
2049 default:
2050 throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2051 }
2052 if (!pTm)
2053 throw Exception("Failed assembling time stamp structure");
2054 return *pTm;
2055 }
2056
2063 return m_timeCreated;
2064 }
2065
2072 return m_timeModified;
2073 }
2074
2086 return _convertTimeStamp(m_timeCreated, base);
2087 }
2088
2100 return _convertTimeStamp(m_timeModified, base);
2101 }
2102
2120 void Archive::removeMember(Object& parent, const Member& member) {
2121 parent.remove(member);
2122 m_isModified = true;
2123 }
2124
2140 void Archive::remove(const Object& obj) {
2141 //FIXME: Should traverse from root object and remove all members associated with this object
2142 if (!obj.uid()) return;
2143 m_allObjects.erase(obj.uid());
2144 m_isModified = true;
2145 }
2146
2159 return m_allObjects[uid];
2160 }
2161
2173 if (!object) return;
2174 object.setVersion(v);
2175 m_isModified = true;
2176 }
2177
2189 if (!object) return;
2190 object.setMinVersion(v);
2191 m_isModified = true;
2192 }
2193
2202 void Archive::setEnumValue(Object& object, uint64_t value) {
2203 if (!object) return;
2204 if (!object.type().isEnum())
2205 throw Exception("Not an enum data type");
2206 Object* pObject = &object;
2207 if (object.type().isPointer()) {
2208 Object& obj = objectByUID(object.uid(1));
2209 if (!obj) return;
2210 pObject = &obj;
2211 }
2212 const int nativeEnumSize = sizeof(enum operation_t);
2213 DataType& type = const_cast<DataType&>( pObject->type() );
2214 // original serializer ("sender") might have had a different word size
2215 // than this machine, adjust type object in this case
2216 if (type.size() != nativeEnumSize) {
2217 type.m_size = nativeEnumSize;
2218 }
2219 pObject->m_data.resize(type.size());
2220 void* ptr = &pObject->m_data[0];
2221 if (type.size() == 1)
2222 *(uint8_t*)ptr = (uint8_t)value;
2223 else if (type.size() == 2)
2224 *(uint16_t*)ptr = (uint16_t)value;
2225 else if (type.size() == 4)
2226 *(uint32_t*)ptr = (uint32_t)value;
2227 else if (type.size() == 8)
2228 *(uint64_t*)ptr = (uint64_t)value;
2229 else
2230 assert(false /* unknown enum type size */);
2231 m_isModified = true;
2232 }
2233
2244 void Archive::setIntValue(Object& object, int64_t value) {
2245 if (!object) return;
2246 if (!object.type().isInteger())
2247 throw Exception("Not an integer data type");
2248 Object* pObject = &object;
2249 if (object.type().isPointer()) {
2250 Object& obj = objectByUID(object.uid(1));
2251 if (!obj) return;
2252 pObject = &obj;
2253 }
2254 const DataType& type = pObject->type();
2255 pObject->m_data.resize(type.size());
2256 void* ptr = &pObject->m_data[0];
2257 if (type.isSigned()) {
2258 if (type.size() == 1)
2259 *(int8_t*)ptr = (int8_t)value;
2260 else if (type.size() == 2)
2261 *(int16_t*)ptr = (int16_t)value;
2262 else if (type.size() == 4)
2263 *(int32_t*)ptr = (int32_t)value;
2264 else if (type.size() == 8)
2265 *(int64_t*)ptr = (int64_t)value;
2266 else
2267 assert(false /* unknown signed int type size */);
2268 } else {
2269 if (type.size() == 1)
2270 *(uint8_t*)ptr = (uint8_t)value;
2271 else if (type.size() == 2)
2272 *(uint16_t*)ptr = (uint16_t)value;
2273 else if (type.size() == 4)
2274 *(uint32_t*)ptr = (uint32_t)value;
2275 else if (type.size() == 8)
2276 *(uint64_t*)ptr = (uint64_t)value;
2277 else
2278 assert(false /* unknown unsigned int type size */);
2279 }
2280 m_isModified = true;
2281 }
2282
2294 void Archive::setRealValue(Object& object, double value) {
2295 if (!object) return;
2296 if (!object.type().isReal())
2297 throw Exception("Not a real data type");
2298 Object* pObject = &object;
2299 if (object.type().isPointer()) {
2300 Object& obj = objectByUID(object.uid(1));
2301 if (!obj) return;
2302 pObject = &obj;
2303 }
2304 const DataType& type = pObject->type();
2305 pObject->m_data.resize(type.size());
2306 void* ptr = &pObject->m_data[0];
2307 if (type.size() == sizeof(float))
2308 *(float*)ptr = (float)value;
2309 else if (type.size() == sizeof(double))
2310 *(double*)ptr = (double)value;
2311 else
2312 assert(false /* unknown real type size */);
2313 m_isModified = true;
2314 }
2315
2324 void Archive::setBoolValue(Object& object, bool value) {
2325 if (!object) return;
2326 if (!object.type().isBool())
2327 throw Exception("Not a bool data type");
2328 Object* pObject = &object;
2329 if (object.type().isPointer()) {
2330 Object& obj = objectByUID(object.uid(1));
2331 if (!obj) return;
2332 pObject = &obj;
2333 }
2334 const DataType& type = pObject->type();
2335 pObject->m_data.resize(type.size());
2336 bool* ptr = (bool*)&pObject->m_data[0];
2337 *ptr = value;
2338 m_isModified = true;
2339 }
2340
2350 if (!object) return;
2351 if (!object.type().isString())
2352 throw Exception("Not a String data type");
2353 Object* pObject = &object;
2354 if (object.type().isPointer()) {
2355 Object& obj = objectByUID(object.uid(1));
2356 if (!obj) return;
2357 pObject = &obj;
2358 }
2359 pObject->m_data.resize(value.length() + 1);
2360 char* ptr = (char*) &pObject->m_data[0];
2361 strcpy(ptr, &value[0]);
2362 m_isModified = true;
2363 }
2364
2378 void Archive::setAutoValue(Object& object, String value) {
2379 if (!object) return;
2380 const DataType& type = object.type();
2381 if (type.isInteger())
2382 setIntValue(object, atoll(value.c_str()));
2383 else if (type.isReal())
2384 setRealValue(object, atof(value.c_str()));
2385 else if (type.isBool()) {
2386 String val = toLowerCase(value);
2387 if (val == "true" || val == "yes" || val == "1")
2388 setBoolValue(object, true);
2389 else if (val == "false" || val == "no" || val == "0")
2390 setBoolValue(object, false);
2391 else
2392 setBoolValue(object, atof(value.c_str()));
2393 } else if (type.isString())
2394 setStringValue(object, value);
2395 else if (type.isEnum())
2396 setEnumValue(object, atoll(value.c_str()));
2397 else
2398 throw Exception("Not a primitive data type");
2399 }
2400
2411 if (!object)
2412 throw Exception("Invalid object");
2413 if (object.type().isClass())
2414 throw Exception("Object is class type");
2415 const Object* pObject = &object;
2416 if (object.type().isPointer()) {
2417 const Object& obj = objectByUID(object.uid(1));
2418 if (!obj) return "";
2419 pObject = &obj;
2420 }
2421 return _primitiveObjectValueToString(*pObject);
2422 }
2423
2433 int64_t Archive::valueAsInt(const Object& object) {
2434 if (!object)
2435 throw Exception("Invalid object");
2436 if (!object.type().isInteger() && !object.type().isEnum())
2437 throw Exception("Object is neither an integer nor an enum");
2438 const Object* pObject = &object;
2439 if (object.type().isPointer()) {
2440 const Object& obj = objectByUID(object.uid(1));
2441 if (!obj) return 0;
2442 pObject = &obj;
2443 }
2444 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2445 }
2446
2456 double Archive::valueAsReal(const Object& object) {
2457 if (!object)
2458 throw Exception("Invalid object");
2459 if (!object.type().isReal())
2460 throw Exception("Object is not an real type");
2461 const Object* pObject = &object;
2462 if (object.type().isPointer()) {
2463 const Object& obj = objectByUID(object.uid(1));
2464 if (!obj) return 0;
2465 pObject = &obj;
2466 }
2467 return _primitiveObjectValueToNumber<double>(*pObject);
2468 }
2469
2478 bool Archive::valueAsBool(const Object& object) {
2479 if (!object)
2480 throw Exception("Invalid object");
2481 if (!object.type().isBool())
2482 throw Exception("Object is not a bool");
2483 const Object* pObject = &object;
2484 if (object.type().isPointer()) {
2485 const Object& obj = objectByUID(object.uid(1));
2486 if (!obj) return 0;
2487 pObject = &obj;
2488 }
2489 return _primitiveObjectValueToNumber<bool>(*pObject);
2490 }
2491
2492 Archive::operation_t Archive::operation() const {
2493 return m_operation;
2494 }
2495
2496 // *************** Archive::Syncer ***************
2497 // *
2498
2499 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2500 : m_dst(dst), m_src(src)
2501 {
2502 const Object srcRootObj = src.rootObject();
2503 const Object dstRootObj = dst.rootObject();
2504 if (!srcRootObj)
2505 throw Exception("No source root object!");
2506 if (!dstRootObj)
2507 throw Exception("Expected destination root object not found!");
2508 syncObject(dstRootObj, srcRootObj);
2509 }
2510
2511 void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2512 assert(srcObj.rawData().size() == dstObj.type().size());
2513 void* pDst = (void*)dstObj.uid().id;
2514 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2515 }
2516
2517 void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2518 assert(dstObj.type().isString());
2519 assert(dstObj.type() == srcObj.type());
2520 String* pDst = (String*)(void*)dstObj.uid().id;
2521 *pDst = (String) (const char*) &srcObj.rawData()[0];
2522 }
2523
2524 void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2525 assert(dstObj.type().isArray());
2526 assert(dstObj.type() == srcObj.type());
2527 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2528 }
2529
2530 void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2531 assert(dstObj.type().isSet());
2532 assert(dstObj.type() == srcObj.type());
2533 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2534 }
2535
2536 void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2537 assert(dstObj.type().isMap());
2538 assert(dstObj.type() == srcObj.type());
2539 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2540 }
2541
2542 void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2543 assert(dstObj.type().isPointer());
2544 assert(dstObj.type() == srcObj.type());
2545 const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2546 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2547 syncObject(pointedDstObject, pointedSrcObject);
2548 }
2549
2550 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2551 if (!dstObj || !srcObj) return; // end of recursion
2552 if (!dstObj.isVersionCompatibleTo(srcObj))
2553 throw Exception("Version incompatible (destination version " +
2554 ToString(dstObj.version()) + " [min. version " +
2555 ToString(dstObj.minVersion()) + "], source version " +
2556 ToString(srcObj.version()) + " [min. version " +
2557 ToString(srcObj.minVersion()) + "])");
2558 if (dstObj.type() != srcObj.type())
2559 throw Exception("Incompatible data structure type (destination type " +
2560 dstObj.type().asLongDescr() + " vs. source type " +
2561 srcObj.type().asLongDescr() + ")");
2562
2563 // prevent syncing this object again, and thus also prevent endless
2564 // loop on data structures with cyclic relations
2565 m_dst.m_allObjects.erase(dstObj.uid());
2566
2567 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2568 if (dstObj.type().isString())
2569 syncString(dstObj, srcObj);
2570 else
2571 syncPrimitive(dstObj, srcObj);
2572 return; // end of recursion
2573 }
2574
2575 if (dstObj.type().isArray()) {
2576 syncArray(dstObj, srcObj);
2577 return;
2578 }
2579
2580 if (dstObj.type().isSet()) {
2581 syncSet(dstObj, srcObj);
2582 return;
2583 }
2584
2585 if (dstObj.type().isMap()) {
2586 syncMap(dstObj, srcObj);
2587 return;
2588 }
2589
2590 if (dstObj.type().isPointer()) {
2591 syncPointer(dstObj, srcObj);
2592 return;
2593 }
2594
2595 assert(dstObj.type().isClass());
2596 for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2597 const Member& srcMember = srcObj.members()[iMember];
2598 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2599 if (!dstMember)
2600 throw Exception("Expected member missing in destination object");
2601 syncMember(dstMember, srcMember);
2602 }
2603 }
2604
2605 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2606 Member dstMember = dstObj.memberNamed(srcMember.name());
2607 if (dstMember)
2608 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2609 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2610 if (members.size() <= 0)
2611 return Member();
2612 if (members.size() == 1)
2613 return members[0];
2614 for (int i = 0; i < members.size(); ++i)
2615 if (members[i].offset() == srcMember.offset())
2616 return members[i];
2617 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2618 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2619 for (int i = 0; i < members.size(); ++i) {
2620 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2621 if (dstSeqNr == srcSeqNr)
2622 return members[i];
2623 }
2624 return Member(); // give up!
2625 }
2626
2627 void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2628 assert(dstMember && srcMember);
2629 assert(dstMember.type() == srcMember.type());
2630 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2631 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2632 syncObject(dstObj, srcObj);
2633 }
2634
2635 // *************** Exception ***************
2636 // *
2637
2638 Exception::Exception() {
2639 }
2640
2641 Exception::Exception(String format, ...) {
2642 va_list arg;
2643 va_start(arg, format);
2644 Message = assemble(format, arg);
2645 va_end(arg);
2646 }
2647
2648 Exception::Exception(String format, va_list arg) {
2649 Message = assemble(format, arg);
2650 }
2651
2658 std::cout << "Serialization::Exception: " << Message << std::endl;
2659 }
2660
2661 String Exception::assemble(String format, va_list arg) {
2662 char* buf = NULL;
2663 vasprintf(&buf, format.c_str(), arg);
2664 String s = buf;
2665 free(buf);
2666 return s;
2667 }
2668
2669} // namespace Serialization
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage()
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
Definition gig.h:98
void * ID
Abstract identifier for serialized C++ objects.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
std::string String
Textual string.
uint32_t Version
Version number data type.
std::vector< UID > UIDChain
Chain of UIDs.
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
time_base_t
To which time zone a certain timing information relates to.
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...