26 #define LIBGIG_SERIALIZATION_INTERNAL 1
28 #include "Serialization.h"
41 #define LIBGIG_EPOCH_TIME ((time_t)0)
48 static UID _createNullUID() {
49 const UID uid = { NULL, 0 };
67 return id != NULL &&
id != (
void*)-1 &&
size;
84 std::map<String,DataType::NativeType> DataType::m_nativeTypes;
132 m_baseTypeName = baseType;
133 m_customTypeName = customType1;
134 m_customTypeName2 = customType2;
186 return m_baseTypeName ==
"class";
224 return m_baseTypeName ==
"String";
242 return m_baseTypeName.substr(0, 3) ==
"int" ||
243 m_baseTypeName.substr(0, 4) ==
"uint";
259 return m_baseTypeName.substr(0, 4) ==
"real";
274 return m_baseTypeName ==
"bool";
289 return m_baseTypeName ==
"enum";
305 return m_baseTypeName ==
"Array";
321 return m_baseTypeName ==
"Set";
337 return m_baseTypeName ==
"Map";
354 return m_baseTypeName.substr(0, 3) ==
"int" ||
377 return m_baseTypeName == other.m_baseTypeName &&
378 m_customTypeName == other.m_customTypeName &&
379 m_customTypeName2 == other.m_customTypeName2 &&
381 m_isPointer == other.m_isPointer;
397 return m_baseTypeName +
"," +
398 m_customTypeName +
"," +
399 m_customTypeName2 +
"," +
401 ToString(m_isPointer);
425 return m_baseTypeName < other.m_baseTypeName ||
426 (m_baseTypeName == other.m_baseTypeName &&
427 (m_customTypeName < other.m_customTypeName ||
428 (m_customTypeName == other.m_customTypeName &&
429 (m_customTypeName2 < other.m_customTypeName2 ||
430 (m_customTypeName2 == other.m_customTypeName2 &&
431 (m_size < other.m_size ||
432 (m_size == other.m_size &&
433 m_isPointer < other.m_isPointer)))))));
466 String s = m_baseTypeName;
467 if (!m_customTypeName.empty())
469 if (!m_customTypeName2.empty())
506 return m_baseTypeName;
509 static String _demangleTypeName(
const char* name) {
511 const size_t MAXLENGTH = 1024;
512 char result[MAXLENGTH];
516 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
525 abi::__cxa_demangle(name, 0, 0, &status);
526 String sResult = result;
528 return (status == 0) ? sResult : name;
569 if (!demangle)
return m_customTypeName;
570 return _demangleTypeName(m_customTypeName.c_str());
581 if (!demangle)
return m_customTypeName2;
582 return _demangleTypeName(m_customTypeName2.c_str());
600 auto itNativeType = m_nativeTypes.find(
id);
601 if (itNativeType == m_nativeTypes.end()) {
603 "(De)serialization Failure: cannot create new instance of "
604 "unknown data type '%s' !\n",
606 assert(
false &&
"You may need to explicitly register this data "
607 "type by either calling "
608 "DataType::registerNativeType<T>() or using class "
609 "NativeDataTypeRegistry");
611 const std::function<
Object(
Archive*)>& allocFn = itNativeType->second.allocFn;
612 return allocFn(archive);
641 m_parentUID = parent.
uid();
761 return m_uid && !m_name.empty() && m_type;
773 return m_uid == other.m_uid &&
774 m_offset == other.m_offset &&
775 m_name == other.m_name &&
776 m_type == other.m_type;
801 return m_uid < other.m_uid ||
802 (m_uid == other.m_uid &&
803 (m_offset < other.m_offset ||
804 (m_offset == other.m_offset &&
805 (m_name < other.m_name ||
806 (m_name == other.m_name &&
807 m_type < other.m_type)))));
866 m_parentUID = parent.
uid();
883 return m_type && !m_uid.empty();
898 return (index < m_uid.size()) ? m_uid[index] :
NO_UID;
917 static void _setNativeValueFromString(
void* ptr,
const DataType& type,
const char* s) {
920 uintptr_t addr = std::stoull(s, NULL, 16);
921 *(
void**)ptr =
reinterpret_cast<void*
>(addr);
925 if (type.
size() == 1)
926 *(int8_t*)ptr = strTo<int8_t>(s);
927 else if (type.
size() == 2)
928 *(int16_t*)ptr = strTo<int16_t>(s);
929 else if (type.
size() == 4)
930 *(int32_t*)ptr = strTo<int32_t>(s);
931 else if (type.
size() == 8)
932 *(int64_t*)ptr = strTo<int64_t>(s);
936 if (type.
size() == 1)
937 *(uint8_t*)ptr = strTo<uint8_t>(s);
938 else if (type.
size() == 2)
939 *(uint16_t*)ptr = strTo<uint16_t>(s);
940 else if (type.
size() == 4)
941 *(uint32_t*)ptr = strTo<uint32_t>(s);
942 else if (type.
size() == 8)
943 *(uint64_t*)ptr = strTo<uint64_t>(s);
947 }
else if (type.
isReal()) {
948 if (type.
size() ==
sizeof(
float))
949 *(
float*)ptr = strTo<float>(s);
950 else if (type.
size() ==
sizeof(double))
951 *(
double*)ptr = strTo<double>(s);
954 }
else if (type.
isBool()) {
955 String lower = toLowerCase(s);
956 const bool b = lower !=
"0" && lower !=
"false" && lower !=
"no";
983 void* ptr = (
void*)
id;
984 _setNativeValueFromString(ptr, m_type, s.c_str());
1058 return m_minVersion;
1120 return m_uid == other.m_uid &&
1121 m_type == other.m_type;
1148 return m_uid < other.m_uid ||
1149 (m_uid == other.m_uid &&
1150 m_type < other.m_type);
1196 void Object::setVersion(
Version v) {
1200 void Object::setMinVersion(
Version v) {
1234 for (
int i = 0; i < m_members.size(); ++i)
1235 if (m_members[i].name() == name)
1236 return m_members[i];
1256 for (
int i = 0; i < m_members.size(); ++i)
1257 if (m_members[i].
uid() ==
uid)
1258 return m_members[i];
1262 void Object::remove(
const Member& member) {
1263 for (
int i = 0; i < m_members.size(); ++i) {
1264 if (m_members[i] == member) {
1265 m_members.erase(m_members.begin() + i);
1287 std::vector<Member> v;
1288 for (
int i = 0; i < m_members.size(); ++i) {
1289 const Member& member = m_members[i];
1291 v.push_back(member);
1328 for (
int i = 0; i < m_members.size(); ++i)
1329 if (m_members[i] == member)
1358 m_isModified =
false;
1359 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1380 m_isModified =
false;
1381 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1408 m_isModified =
false;
1409 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1413 Archive::~Archive() {
1427 return m_allObjects[m_root];
1431 return ToString(data.length()) +
":" + data;
1434 static String _encode(
const UID& uid) {
1436 s += _encodeBlob(ToString(
size_t(uid.id)));
1437 s += _encodeBlob(ToString(
size_t(uid.size)));
1438 return _encodeBlob(s);
1441 static String _encode(
const time_t& time) {
1442 return _encodeBlob(ToString(time));
1445 static String _encode(
const DataType& type) {
1449 s += _encodeBlob(type.baseTypeName());
1450 s += _encodeBlob(type.customTypeName());
1451 s += _encodeBlob(ToString(type.size()));
1452 s += _encodeBlob(ToString(type.isPointer()));
1455 s += _encodeBlob(type.customTypeName2());
1457 return _encodeBlob(s);
1460 static String _encode(
const UIDChain& chain) {
1462 for (
int i = 0; i < chain.size(); ++i)
1463 s += _encode(chain[i]);
1464 return _encodeBlob(s);
1467 static String _encode(
const Member& member) {
1469 s += _encode(member.uid());
1470 s += _encodeBlob(ToString(member.offset()));
1471 s += _encodeBlob(member.name());
1472 s += _encode(member.type());
1473 return _encodeBlob(s);
1476 static String _encode(
const std::vector<Member>& members) {
1478 for (
int i = 0; i < members.size(); ++i)
1479 s += _encode(members[i]);
1480 return _encodeBlob(s);
1483 static String _primitiveObjectValueToString(
const Object& obj) {
1485 const DataType& type = obj.type();
1486 const ID&
id = obj.uid().id;
1487 void* ptr = obj.m_data.empty() ? (
void*)
id : (
void*)&obj.m_data[0];
1488 if (!obj.m_data.empty())
1489 assert(type.size() == obj.m_data.size());
1490 if (type.isPrimitive() && !type.isPointer()) {
1491 if (type.isInteger() || type.isEnum()) {
1492 if (type.isSigned()) {
1493 if (type.size() == 1)
1494 s = ToString((int16_t)*(int8_t*)ptr);
1495 else if (type.size() == 2)
1496 s = ToString(*(int16_t*)ptr);
1497 else if (type.size() == 4)
1498 s = ToString(*(int32_t*)ptr);
1499 else if (type.size() == 8)
1500 s = ToString(*(int64_t*)ptr);
1504 if (type.size() == 1)
1505 s = ToString((uint16_t)*(uint8_t*)ptr);
1506 else if (type.size() == 2)
1507 s = ToString(*(uint16_t*)ptr);
1508 else if (type.size() == 4)
1509 s = ToString(*(uint32_t*)ptr);
1510 else if (type.size() == 8)
1511 s = ToString(*(uint64_t*)ptr);
1515 }
else if (type.isReal()) {
1516 if (type.size() ==
sizeof(
float))
1517 s = ToString(*(
float*)ptr);
1518 else if (type.size() ==
sizeof(
double))
1519 s = ToString(*(
double*)ptr);
1522 }
else if (type.isBool()) {
1523 s = ToString(*(
bool*)ptr);
1524 }
else if (type.isString()) {
1525 s = obj.m_data.empty() ? *(String*)ptr :
String((
const char*)ptr);
1533 template<
typename T>
1534 inline T _stringToNumber(
const String& s) {
1539 inline int64_t _stringToNumber(
const String& s) {
1540 return strTo<int64_t>(s);
1544 inline double _stringToNumber(
const String& s) {
1545 return strTo<double>(s);
1549 inline bool _stringToNumber(
const String& s) {
1550 return strTo<bool>(s);
1553 template<
typename T>
1554 static T _primitiveObjectValueToNumber(
const Object& obj) {
1556 const DataType& type = obj.type();
1557 const ID&
id = obj.uid().id;
1558 void* ptr = obj.m_data.empty() ? (
void*)
id : (
void*)&obj.m_data[0];
1559 if (!obj.m_data.empty())
1560 assert(type.size() == obj.m_data.size());
1561 if (type.isPrimitive() && !type.isPointer()) {
1562 if (type.isInteger() || type.isEnum()) {
1563 if (type.isSigned()) {
1564 if (type.size() == 1)
1565 value = (T)*(int8_t*)ptr;
1566 else if (type.size() == 2)
1567 value = (T)*(int16_t*)ptr;
1568 else if (type.size() == 4)
1569 value = (T)*(int32_t*)ptr;
1570 else if (type.size() == 8)
1571 value = (T)*(int64_t*)ptr;
1575 if (type.size() == 1)
1576 value = (T)*(uint8_t*)ptr;
1577 else if (type.size() == 2)
1578 value = (T)*(uint16_t*)ptr;
1579 else if (type.size() == 4)
1580 value = (T)*(uint32_t*)ptr;
1581 else if (type.size() == 8)
1582 value = (T)*(uint64_t*)ptr;
1586 }
else if (type.isReal()) {
1587 if (type.size() ==
sizeof(
float))
1588 value = (T)*(
float*)ptr;
1589 else if (type.size() ==
sizeof(double))
1590 value = (T)*(
double*)ptr;
1593 }
else if (type.isBool()) {
1594 value = (T)*(
bool*)ptr;
1595 }
else if (type.isString()) {
1596 value = _stringToNumber<T>(
1597 obj.m_data.empty() ? *(String*)ptr : String((
const char*)ptr)
1606 static String _encodePrimitiveValue(
const Object& obj) {
1607 return _encodeBlob( _primitiveObjectValueToString(obj) );
1610 static String _encode(
const Object& obj) {
1612 s += _encode(obj.type());
1613 s += _encodeBlob(ToString(obj.version()));
1614 s += _encodeBlob(ToString(obj.minVersion()));
1615 s += _encode(obj.uidChain());
1616 s += _encode(obj.members());
1617 s += _encodePrimitiveValue(obj);
1619 s += _encode(obj.parentUID());
1621 return _encodeBlob(s);
1624 String _encode(
const Archive::ObjectPool& objects) {
1626 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1627 itObject != objects.end(); ++itObject)
1629 const Object& obj = itObject->second;
1632 return _encodeBlob(s);
1649 #define MAGIC_START "Srx1v"
1650 #define ENCODING_FORMAT_MINOR_VERSION 2
1652 String Archive::_encodeRootBlob() {
1654 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1655 s += _encode(m_root);
1656 s += _encode(m_allObjects);
1657 s += _encodeBlob(m_name);
1658 s += _encodeBlob(m_comment);
1659 s += _encode(m_timeCreated);
1660 s += _encode(m_timeModified);
1661 return _encodeBlob(s);
1664 void Archive::encode() {
1666 String s = MAGIC_START;
1667 m_timeModified = time(NULL);
1668 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1669 m_timeCreated = m_timeModified;
1670 s += _encodeRootBlob();
1671 m_rawData.resize(s.length() + 1);
1672 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1673 m_isModified =
false;
1681 static _Blob _decodeBlob(
const char* p,
const char* end,
bool bThrow =
true) {
1682 if (!bThrow && p >= end) {
1683 const _Blob blob = { p, end };
1689 throw Exception(
"Decode Error: Missing blob");
1691 if (c ==
':')
break;
1692 if (c < '0' || c >
'9')
1693 throw Exception(
"Decode Error: Missing blob size");
1695 sz += size_t(c -
'0');
1699 throw Exception(
"Decode Error: Premature end of blob");
1700 const _Blob blob = { p, p + sz };
1704 template<
typename T_
int>
1705 static T_int _popIntBlob(
const char*& p,
const char* end) {
1706 _Blob blob = _decodeBlob(p, end);
1713 throw Exception(
"Decode Error: premature end of int blob");
1718 for (; p < end; ++p) {
1720 if (c < '0' || c >
'9')
1721 throw Exception(
"Decode Error: Invalid int blob format");
1723 i += size_t(c -
'0');
1728 template<
typename T_
int>
1729 static void _popIntBlob(
const char*& p,
const char* end,
RawData& rawData) {
1730 const T_int i = _popIntBlob<T_int>(p, end);
1731 *(T_int*)&rawData[0] = i;
1734 template<
typename T_real>
1735 static T_real _popRealBlob(
const char*& p,
const char* end) {
1736 _Blob blob = _decodeBlob(p, end);
1740 if (p >= end || (end - p) < 1)
1741 throw Exception(
"Decode Error: premature end of real blob");
1743 String s(p,
size_t(end - p));
1746 if (
sizeof(T_real) <=
sizeof(
double))
1747 r = strTo<T_real>(s);
1756 template<
typename T_real>
1757 static void _popRealBlob(
const char*& p,
const char* end,
RawData& rawData) {
1758 const T_real r = _popRealBlob<T_real>(p, end);
1759 *(T_real*)&rawData[0] = r;
1762 static String _popStringBlob(
const char*& p,
const char* end) {
1763 _Blob blob = _decodeBlob(p, end);
1767 throw Exception(
"Decode Error: missing String blob");
1769 const size_t sz = end - p;
1771 memcpy(&s[0], p, sz);
1776 static void _popStringBlob(
const char*& p,
const char* end,
RawData& rawData) {
1777 String s = _popStringBlob(p, end);
1778 rawData.resize(s.length() + 1);
1779 strcpy((
char*)&rawData[0], &s[0]);
1782 static time_t _popTimeBlob(
const char*& p,
const char* end) {
1783 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1787 static DataType _popDataTypeBlob(
const char*& p,
const char* end) {
1788 _Blob blob = _decodeBlob(p, end);
1795 type.m_baseTypeName = _popStringBlob(p, end);
1796 type.m_customTypeName = _popStringBlob(p, end);
1797 type.m_size = _popIntBlob<int>(p, end);
1798 type.m_isPointer = _popIntBlob<bool>(p, end);
1802 type.m_customTypeName2 = _popStringBlob(p, end);
1807 static UID _popUIDBlob(
const char*& p,
const char* end) {
1808 _Blob blob = _decodeBlob(p, end);
1813 throw Exception(
"Decode Error: premature end of UID blob");
1815 const ID id = (
ID) _popIntBlob<size_t>(p, end);
1816 const size_t size = _popIntBlob<size_t>(p, end);
1818 const UID uid = { id, size };
1822 static UIDChain _popUIDChainBlob(
const char*& p,
const char* end) {
1823 _Blob blob = _decodeBlob(p, end);
1829 const UID uid = _popUIDBlob(p, end);
1830 chain.push_back(uid);
1832 assert(!chain.empty());
1836 static Member _popMemberBlob(
const char*& p,
const char* end) {
1837 _Blob blob = _decodeBlob(p, end,
false);
1842 if (p >= end)
return m;
1844 m.m_uid = _popUIDBlob(p, end);
1845 m.m_offset = _popIntBlob<ssize_t>(p, end);
1846 m.m_name = _popStringBlob(p, end);
1847 m.m_type = _popDataTypeBlob(p, end);
1849 assert(!m.name().empty());
1850 assert(m.uid().isValid());
1854 static std::vector<Member> _popMembersBlob(
const char*& p,
const char* end) {
1855 _Blob blob = _decodeBlob(p, end,
false);
1859 std::vector<Member> members;
1861 const Member member = _popMemberBlob(p, end);
1863 members.push_back(member);
1870 static void _popPrimitiveValue(
const char*& p,
const char* end, Object& obj) {
1871 const DataType& type = obj.type();
1872 if (type.isPrimitive() && !type.isPointer()) {
1873 obj.m_data.resize(type.size());
1874 if (type.isInteger() || type.isEnum()) {
1875 if (type.isSigned()) {
1876 if (type.size() == 1)
1877 _popIntBlob<int8_t>(p, end, obj.m_data);
1878 else if (type.size() == 2)
1879 _popIntBlob<int16_t>(p, end, obj.m_data);
1880 else if (type.size() == 4)
1881 _popIntBlob<int32_t>(p, end, obj.m_data);
1882 else if (type.size() == 8)
1883 _popIntBlob<int64_t>(p, end, obj.m_data);
1887 if (type.size() == 1)
1888 _popIntBlob<uint8_t>(p, end, obj.m_data);
1889 else if (type.size() == 2)
1890 _popIntBlob<uint16_t>(p, end, obj.m_data);
1891 else if (type.size() == 4)
1892 _popIntBlob<uint32_t>(p, end, obj.m_data);
1893 else if (type.size() == 8)
1894 _popIntBlob<uint64_t>(p, end, obj.m_data);
1898 }
else if (type.isReal()) {
1899 if (type.size() ==
sizeof(
float))
1900 _popRealBlob<float>(p, end, obj.m_data);
1901 else if (type.size() ==
sizeof(
double))
1902 _popRealBlob<double>(p, end, obj.m_data);
1905 }
else if (type.isBool()) {
1906 _popIntBlob<uint8_t>(p, end, obj.m_data);
1907 }
else if (type.isString()) {
1908 _popStringBlob(p, end, obj.m_data);
1915 _Blob blob = _decodeBlob(p, end,
false);
1921 static Object _popObjectBlob(
const char*& p,
const char* end) {
1922 _Blob blob = _decodeBlob(p, end,
false);
1927 if (p >= end)
return obj;
1929 obj.m_type = _popDataTypeBlob(p, end);
1930 obj.m_version = _popIntBlob<Version>(p, end);
1931 obj.m_minVersion = _popIntBlob<Version>(p, end);
1932 obj.m_uid = _popUIDChainBlob(p, end);
1933 obj.m_members = _popMembersBlob(p, end);
1934 _popPrimitiveValue(p, end, obj);
1939 obj.m_parentUID = _popUIDBlob(p, end);
1944 void Archive::_popObjectsBlob(
const char*& p,
const char* end) {
1945 _Blob blob = _decodeBlob(p, end,
false);
1950 throw Exception(
"Decode Error: Premature end of objects blob");
1953 const Object obj = _popObjectBlob(p, end);
1955 m_allObjects[obj.uid()] = obj;
1959 void Archive::_popRootBlob(
const char*& p,
const char* end) {
1960 _Blob blob = _decodeBlob(p, end,
false);
1965 throw Exception(
"Decode Error: Premature end of root blob");
1969 const int formatMinorVersion = _popIntBlob<int>(p, end);
1971 m_root = _popUIDBlob(p, end);
1973 throw Exception(
"Decode Error: No root object");
1975 _popObjectsBlob(p, end);
1976 if (!m_allObjects[m_root])
1977 throw Exception(
"Decode Error: Missing declared root object");
1979 m_name = _popStringBlob(p, end);
1980 m_comment = _popStringBlob(p, end);
1981 m_timeCreated = _popTimeBlob(p, end);
1982 m_timeModified = _popTimeBlob(p, end);
2002 m_allObjects.clear();
2003 m_isModified =
false;
2004 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2005 const char* p = (
const char*) &data[0];
2006 const char* end = p + data.size();
2007 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
2008 throw Exception(
"Decode Error: Magic start missing!");
2009 p += strlen(MAGIC_START);
2010 _popRootBlob(p, end);
2036 memcpy(&
rawData[0], data, size);
2056 if (m_isModified) encode();
2084 return m_isModified;
2093 m_allObjects.clear();
2097 m_isModified =
false;
2098 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2122 if (m_name ==
name)
return;
2124 m_isModified =
true;
2148 if (m_comment ==
comment)
return;
2150 m_isModified =
true;
2153 static tm _convertTimeStamp(
const time_t& time,
time_base_t base) {
2157 pTm = localtime(&time);
2160 pTm = gmtime(&time);
2163 throw Exception(
"Time stamp with unknown time base (" + ToString((int64_t)base) +
") requested");
2166 throw Exception(
"Failed assembling time stamp structure");
2176 return m_timeCreated;
2185 return m_timeModified;
2199 return _convertTimeStamp(m_timeCreated, base);
2213 return _convertTimeStamp(m_timeModified, base);
2234 parent.remove(member);
2235 m_isModified =
true;
2255 if (!obj.
uid())
return;
2256 m_allObjects.erase(obj.
uid());
2257 m_isModified =
true;
2273 return m_allObjects[uid];
2291 ObjectPool::iterator it = m_allObjects.find(uid);
2292 if (it != m_allObjects.end())
2297 std::map<size_t,UID> matches;
2298 for (
const auto& it : m_allObjects)
2299 if (it.first.id == uid.
id && it.first.size > uid.
size)
2300 matches[it.first.size] = it.first;
2302 if (matches.empty())
2303 return ObjectPool::invalidObject();
2306 return m_allObjects[matches.begin()->second];
2327 return m_allObjects[member.
parentUID()];
2341 if (!
object)
return;
2342 object.setVersion(v);
2343 m_isModified =
true;
2357 if (!
object)
return;
2358 object.setMinVersion(v);
2359 m_isModified =
true;
2371 if (!
object)
return;
2372 if (!
object.type().isEnum())
2373 throw Exception(
"Not an enum data type");
2374 Object* pObject = &object;
2375 if (
object.type().isPointer()) {
2380 const int nativeEnumSize =
sizeof(
enum operation_t);
2384 if (type.
size() != nativeEnumSize) {
2385 type.m_size = nativeEnumSize;
2387 pObject->m_data.resize(type.
size());
2388 void* ptr = &pObject->m_data[0];
2389 if (type.
size() == 1)
2390 *(uint8_t*)ptr = (uint8_t)value;
2391 else if (type.
size() == 2)
2392 *(uint16_t*)ptr = (uint16_t)value;
2393 else if (type.
size() == 4)
2394 *(uint32_t*)ptr = (uint32_t)value;
2395 else if (type.
size() == 8)
2396 *(uint64_t*)ptr = (uint64_t)value;
2399 m_isModified =
true;
2413 if (!
object)
return;
2414 if (!
object.type().isInteger())
2415 throw Exception(
"Not an integer data type");
2416 Object* pObject = &object;
2417 if (
object.type().isPointer()) {
2423 pObject->m_data.resize(type.
size());
2424 void* ptr = &pObject->m_data[0];
2426 if (type.
size() == 1)
2427 *(int8_t*)ptr = (int8_t)value;
2428 else if (type.
size() == 2)
2429 *(int16_t*)ptr = (int16_t)value;
2430 else if (type.
size() == 4)
2431 *(int32_t*)ptr = (int32_t)value;
2432 else if (type.
size() == 8)
2433 *(int64_t*)ptr = (int64_t)value;
2437 if (type.
size() == 1)
2438 *(uint8_t*)ptr = (uint8_t)value;
2439 else if (type.
size() == 2)
2440 *(uint16_t*)ptr = (uint16_t)value;
2441 else if (type.
size() == 4)
2442 *(uint32_t*)ptr = (uint32_t)value;
2443 else if (type.
size() == 8)
2444 *(uint64_t*)ptr = (uint64_t)value;
2448 m_isModified =
true;
2463 if (!
object)
return;
2464 if (!
object.type().isReal())
2465 throw Exception(
"Not a real data type");
2466 Object* pObject = &object;
2467 if (
object.type().isPointer()) {
2473 pObject->m_data.resize(type.
size());
2474 void* ptr = &pObject->m_data[0];
2475 if (type.
size() ==
sizeof(
float))
2476 *(
float*)ptr = (
float)value;
2477 else if (type.
size() ==
sizeof(double))
2478 *(
double*)ptr = (
double)value;
2481 m_isModified =
true;
2493 if (!
object)
return;
2494 if (!
object.type().isBool())
2495 throw Exception(
"Not a bool data type");
2496 Object* pObject = &object;
2497 if (
object.type().isPointer()) {
2503 pObject->m_data.resize(type.
size());
2504 bool* ptr = (
bool*)&pObject->m_data[0];
2506 m_isModified =
true;
2518 if (!
object)
return;
2519 if (!
object.type().isString())
2520 throw Exception(
"Not a String data type");
2521 Object* pObject = &object;
2522 if (
object.type().isPointer()) {
2527 pObject->m_data.resize(value.length() + 1);
2528 char* ptr = (
char*) &pObject->m_data[0];
2529 strcpy(ptr, &value[0]);
2530 m_isModified =
true;
2547 if (!
object)
return;
2548 const DataType& type =
object.type();
2553 else if (type.
isBool()) {
2554 String val = toLowerCase(value);
2555 if (val ==
"true" || val ==
"yes" || val ==
"1")
2557 else if (val ==
"false" || val ==
"no" || val ==
"0")
2566 throw Exception(
"Not a primitive data type");
2581 if (
object.type().isClass())
2582 throw Exception(
"Object is class type");
2583 const Object* pObject = &object;
2584 if (
object.type().isPointer()) {
2586 if (!obj)
return "";
2589 return _primitiveObjectValueToString(*pObject);
2604 if (!
object.type().isInteger() && !
object.type().isEnum())
2605 throw Exception(
"Object is neither an integer nor an enum");
2606 const Object* pObject = &object;
2607 if (
object.type().isPointer()) {
2612 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2627 if (!
object.type().isReal())
2628 throw Exception(
"Object is not an real type");
2629 const Object* pObject = &object;
2630 if (
object.type().isPointer()) {
2635 return _primitiveObjectValueToNumber<double>(*pObject);
2649 if (!
object.type().isBool())
2650 throw Exception(
"Object is not a bool");
2651 const Object* pObject = &object;
2652 if (
object.type().isPointer()) {
2657 return _primitiveObjectValueToNumber<bool>(*pObject);
2667 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2668 : m_dst(dst), m_src(src)
2670 const Object srcRootObj = src.rootObject();
2671 const Object dstRootObj = dst.rootObject();
2673 throw Exception(
"No source root object!");
2675 throw Exception(
"Expected destination root object not found!");
2676 syncObject(dstRootObj, srcRootObj);
2679 void Archive::Syncer::syncPrimitive(
const Object& dstObj,
const Object& srcObj) {
2680 assert(srcObj.rawData().size() == dstObj.type().size());
2681 void* pDst = (
void*)dstObj.uid().id;
2682 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2685 void Archive::Syncer::syncString(
const Object& dstObj,
const Object& srcObj) {
2686 assert(dstObj.type().isString());
2687 assert(dstObj.type() == srcObj.type());
2688 String* pDst = (String*)(
void*)dstObj.uid().id;
2689 *pDst = (
String) (
const char*) &srcObj.rawData()[0];
2692 void Archive::Syncer::syncArray(
const Object& dstObj,
const Object& srcObj) {
2693 assert(dstObj.type().isArray());
2694 assert(dstObj.type() == srcObj.type());
2695 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2698 void Archive::Syncer::syncSet(
const Object& dstObj,
const Object& srcObj) {
2699 assert(dstObj.type().isSet());
2700 assert(dstObj.type() == srcObj.type());
2701 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2704 void Archive::Syncer::syncMap(
const Object& dstObj,
const Object& srcObj) {
2705 assert(dstObj.type().isMap());
2706 assert(dstObj.type() == srcObj.type());
2707 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2710 void Archive::Syncer::syncPointer(
const Object& dstObj,
const Object& srcObj) {
2711 assert(dstObj.type().isPointer());
2712 assert(dstObj.type() == srcObj.type());
2713 void** ppDst = (
void**)dstObj.uid().id;
2714 if (!srcObj.uid(1)) {
2718 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2719 assert(pointedSrcObject);
2720 std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2721 if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) {
2722 assert(uidRelation != m_counterparts.end());
2723 const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2724 assert(pointedDstObject);
2725 *ppDst = (
void*)pointedDstObject.uid().id;
2727 assert(pointedSrcObject.type());
2728 Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2729 assert(pointedDstObject);
2731 m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2732 *ppDst = (
void*)pointedDstObject.uid().id;
2733 syncObject(pointedDstObject, pointedSrcObject);
2737 void Archive::Syncer::syncObject(
const Object& dstObj,
const Object& srcObj) {
2738 assert(dstObj && srcObj);
2748 const bool alreadySynced =
2749 !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2756 if (!dstObj.isVersionCompatibleTo(srcObj))
2757 throw Exception(
"Version incompatible (destination version " +
2758 ToString(dstObj.version()) +
" [min. version " +
2759 ToString(dstObj.minVersion()) +
"], source version " +
2760 ToString(srcObj.version()) +
" [min. version " +
2761 ToString(srcObj.minVersion()) +
"])");
2762 if (dstObj.type() != srcObj.type())
2763 throw Exception(
"Incompatible data structure type (destination type " +
2764 dstObj.type().asLongDescr() +
" vs. source type " +
2765 srcObj.type().asLongDescr() +
")");
2767 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2768 if (dstObj.type().isString())
2769 syncString(dstObj, srcObj);
2771 syncPrimitive(dstObj, srcObj);
2775 if (dstObj.type().isArray()) {
2776 syncArray(dstObj, srcObj);
2780 if (dstObj.type().isSet()) {
2781 syncSet(dstObj, srcObj);
2785 if (dstObj.type().isMap()) {
2786 syncMap(dstObj, srcObj);
2790 if (dstObj.type().isPointer()) {
2791 syncPointer(dstObj, srcObj);
2795 assert(dstObj.type().isClass());
2796 for (
int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2797 const Member& srcMember = srcObj.members()[iMember];
2798 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2800 throw Exception(
"Expected member missing in destination object");
2801 syncMember(dstMember, srcMember);
2805 Member Archive::Syncer::dstMemberMatching(
const Object& dstObj,
const Object& srcObj,
const Member& srcMember) {
2806 Member dstMember = dstObj.memberNamed(srcMember.name());
2808 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2809 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2810 if (members.size() <= 0)
2812 if (members.size() == 1)
2814 for (
int i = 0; i < members.size(); ++i)
2815 if (members[i].offset() == srcMember.offset())
2817 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2818 assert(srcSeqNr >= 0);
2819 for (
int i = 0; i < members.size(); ++i) {
2820 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2821 if (dstSeqNr == srcSeqNr)
2827 void Archive::Syncer::syncMember(
const Member& dstMember,
const Member& srcMember) {
2828 assert(dstMember && srcMember);
2829 assert(dstMember.type() == srcMember.type());
2830 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2831 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2832 syncObject(dstObj, srcObj);
2838 Exception::Exception() {
2841 Exception::Exception(String format, ...) {
2843 va_start(arg, format);
2844 Message = assemble(format, arg);
2848 Exception::Exception(String format, va_list arg) {
2849 Message = assemble(format, arg);
2858 std::cout <<
"Serialization::Exception: " << Message << std::endl;
2861 String Exception::assemble(
String format, va_list arg) {
2863 vasprintf(&buf, format.c_str(), arg);
Destination container for serialization, and source container for deserialization.
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.
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.
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.
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.
Serialization / deserialization framework.
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...