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