26 #define LIBGIG_SERIALIZATION_INTERNAL 1
28 #include "Serialization.h"
42 #define LIBGIG_EPOCH_TIME ((time_t)0)
49 static UID _createNullUID() {
50 const UID uid = { NULL, 0 };
68 return id != NULL &&
id != (
void*)-1 &&
size;
133 m_baseTypeName = baseType;
134 m_customTypeName = customType1;
135 m_customTypeName2 = customType2;
187 return m_baseTypeName ==
"class";
225 return m_baseTypeName ==
"String";
243 return m_baseTypeName.substr(0, 3) ==
"int" ||
244 m_baseTypeName.substr(0, 4) ==
"uint";
260 return m_baseTypeName.substr(0, 4) ==
"real";
275 return m_baseTypeName ==
"bool";
290 return m_baseTypeName ==
"enum";
306 return m_baseTypeName ==
"Array";
322 return m_baseTypeName ==
"Set";
338 return m_baseTypeName ==
"Map";
355 return m_baseTypeName.substr(0, 3) ==
"int" ||
378 return m_baseTypeName == other.m_baseTypeName &&
379 m_customTypeName == other.m_customTypeName &&
380 m_customTypeName2 == other.m_customTypeName2 &&
382 m_isPointer == other.m_isPointer;
398 return m_baseTypeName +
"," +
399 m_customTypeName +
"," +
400 m_customTypeName2 +
"," +
401 ToString(m_size) +
"," +
403 ToString(m_isPointer);
427 return m_baseTypeName < other.m_baseTypeName ||
428 (m_baseTypeName == other.m_baseTypeName &&
429 (m_customTypeName < other.m_customTypeName ||
430 (m_customTypeName == other.m_customTypeName &&
431 (m_customTypeName2 < other.m_customTypeName2 ||
432 (m_customTypeName2 == other.m_customTypeName2 &&
433 (m_size < other.m_size ||
434 (m_size == other.m_size &&
435 m_isPointer < other.m_isPointer)))))));
468 String s = m_baseTypeName;
469 if (!m_customTypeName.empty())
471 if (!m_customTypeName2.empty())
508 return m_baseTypeName;
511 static String _demangleTypeName(
const char* name) {
513 const size_t MAXLENGTH = 1024;
514 char result[MAXLENGTH];
518 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
527 abi::__cxa_demangle(name, 0, 0, &status);
528 String sResult = result;
530 return (status == 0) ? sResult : name;
571 if (!demangle)
return m_customTypeName;
572 return _demangleTypeName(m_customTypeName.c_str());
583 if (!demangle)
return m_customTypeName2;
584 return _demangleTypeName(m_customTypeName2.c_str());
602 auto itAllocFn = m_allocFns.find(
id);
603 assert(itAllocFn != m_allocFns.end());
604 const std::function<
Object(
Archive*)>& allocFn = itAllocFn->second;
605 return allocFn(archive);
634 m_parentUID = parent.
uid();
754 return m_uid && !m_name.empty() && m_type;
766 return m_uid == other.m_uid &&
767 m_offset == other.m_offset &&
768 m_name == other.m_name &&
769 m_type == other.m_type;
794 return m_uid < other.m_uid ||
795 (m_uid == other.m_uid &&
796 (m_offset < other.m_offset ||
797 (m_offset == other.m_offset &&
798 (m_name < other.m_name ||
799 (m_name == other.m_name &&
800 m_type < other.m_type)))));
859 m_parentUID = parent.
uid();
876 return m_type && !m_uid.empty();
891 return (index < m_uid.size()) ? m_uid[index] :
NO_UID;
910 static void _setNativeValueFromString(
void* ptr,
const DataType& type,
const char* s) {
913 uintptr_t addr = std::stoull(s, NULL, 16);
914 *(
void**)ptr =
reinterpret_cast<void*
>(addr);
918 if (type.
size() == 1)
919 *(int8_t*)ptr = (int8_t) atoll(s);
920 else if (type.
size() == 2)
921 *(int16_t*)ptr = (int16_t) atoll(s);
922 else if (type.
size() == 4)
923 *(int32_t*)ptr = (int32_t) atoll(s);
924 else if (type.
size() == 8)
925 *(int64_t*)ptr = (int64_t) atoll(s);
929 if (type.
size() == 1)
930 *(uint8_t*)ptr = (uint8_t) atoll(s);
931 else if (type.
size() == 2)
932 *(uint16_t*)ptr = (uint16_t) atoll(s);
933 else if (type.
size() == 4)
934 *(uint32_t*)ptr = (uint32_t) atoll(s);
935 else if (type.
size() == 8)
936 *(uint64_t*)ptr = (uint64_t) atoll(s);
940 }
else if (type.
isReal()) {
941 if (type.
size() ==
sizeof(
float))
942 *(
float*)ptr = (
float) atof(s);
943 else if (type.
size() ==
sizeof(
double))
944 *(
double*)ptr = (
double) atof(s);
947 }
else if (type.
isBool()) {
948 String lower = toLowerCase(s);
949 const bool b = lower !=
"0" && lower !=
"false" && lower !=
"no";
976 void* ptr = (
void*)
id;
977 _setNativeValueFromString(ptr, m_type, s.c_str());
1051 return m_minVersion;
1113 return m_uid == other.m_uid &&
1114 m_type == other.m_type;
1141 return m_uid < other.m_uid ||
1142 (m_uid == other.m_uid &&
1143 m_type < other.m_type);
1189 void Object::setVersion(
Version v) {
1193 void Object::setMinVersion(
Version v) {
1227 for (
int i = 0; i < m_members.size(); ++i)
1228 if (m_members[i].name() == name)
1229 return m_members[i];
1249 for (
int i = 0; i < m_members.size(); ++i)
1250 if (m_members[i].
uid() ==
uid)
1251 return m_members[i];
1255 void Object::remove(
const Member& member) {
1256 for (
int i = 0; i < m_members.size(); ++i) {
1257 if (m_members[i] == member) {
1258 m_members.erase(m_members.begin() + i);
1280 std::vector<Member> v;
1281 for (
int i = 0; i < m_members.size(); ++i) {
1282 const Member& member = m_members[i];
1284 v.push_back(member);
1321 for (
int i = 0; i < m_members.size(); ++i)
1322 if (m_members[i] == member)
1351 m_isModified =
false;
1352 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1373 m_isModified =
false;
1374 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1401 m_isModified =
false;
1402 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1406 Archive::~Archive() {
1420 return m_allObjects[m_root];
1424 return ToString(data.length()) +
":" + data;
1427 static String _encode(
const UID& uid) {
1429 s += _encodeBlob(ToString(
size_t(uid.id)));
1430 s += _encodeBlob(ToString(
size_t(uid.size)));
1431 return _encodeBlob(s);
1434 static String _encode(
const time_t& time) {
1435 return _encodeBlob(ToString(time));
1438 static String _encode(
const DataType& type) {
1442 s += _encodeBlob(type.baseTypeName());
1443 s += _encodeBlob(type.customTypeName());
1444 s += _encodeBlob(ToString(type.size()));
1445 s += _encodeBlob(ToString(type.isPointer()));
1448 s += _encodeBlob(type.customTypeName2());
1450 return _encodeBlob(s);
1453 static String _encode(
const UIDChain& chain) {
1455 for (
int i = 0; i < chain.size(); ++i)
1456 s += _encode(chain[i]);
1457 return _encodeBlob(s);
1460 static String _encode(
const Member& member) {
1462 s += _encode(member.uid());
1463 s += _encodeBlob(ToString(member.offset()));
1464 s += _encodeBlob(member.name());
1465 s += _encode(member.type());
1466 return _encodeBlob(s);
1469 static String _encode(
const std::vector<Member>& members) {
1471 for (
int i = 0; i < members.size(); ++i)
1472 s += _encode(members[i]);
1473 return _encodeBlob(s);
1476 static String _primitiveObjectValueToString(
const Object& obj) {
1478 const DataType& type = obj.type();
1479 const ID&
id = obj.uid().id;
1480 void* ptr = obj.m_data.empty() ? (
void*)
id : (
void*)&obj.m_data[0];
1481 if (!obj.m_data.empty())
1482 assert(type.size() == obj.m_data.size());
1483 if (type.isPrimitive() && !type.isPointer()) {
1484 if (type.isInteger() || type.isEnum()) {
1485 if (type.isSigned()) {
1486 if (type.size() == 1)
1487 s = ToString((int16_t)*(int8_t*)ptr);
1488 else if (type.size() == 2)
1489 s = ToString(*(int16_t*)ptr);
1490 else if (type.size() == 4)
1491 s = ToString(*(int32_t*)ptr);
1492 else if (type.size() == 8)
1493 s = ToString(*(int64_t*)ptr);
1497 if (type.size() == 1)
1498 s = ToString((uint16_t)*(uint8_t*)ptr);
1499 else if (type.size() == 2)
1500 s = ToString(*(uint16_t*)ptr);
1501 else if (type.size() == 4)
1502 s = ToString(*(uint32_t*)ptr);
1503 else if (type.size() == 8)
1504 s = ToString(*(uint64_t*)ptr);
1508 }
else if (type.isReal()) {
1509 if (type.size() ==
sizeof(
float))
1510 s = ToString(*(
float*)ptr);
1511 else if (type.size() ==
sizeof(
double))
1512 s = ToString(*(
double*)ptr);
1515 }
else if (type.isBool()) {
1516 s = ToString(*(
bool*)ptr);
1517 }
else if (type.isString()) {
1518 s = obj.m_data.empty() ? *(String*)ptr :
String((
const char*)ptr);
1526 template<
typename T>
1527 inline T _stringToNumber(
const String& s) {
1532 inline int64_t _stringToNumber(
const String& s) {
1533 return atoll(s.c_str());
1537 inline double _stringToNumber(
const String& s) {
1538 return atof(s.c_str());
1542 inline bool _stringToNumber(
const String& s) {
1543 return (
bool) atoll(s.c_str());
1546 template<
typename T>
1547 static T _primitiveObjectValueToNumber(
const Object& obj) {
1549 const DataType& type = obj.type();
1550 const ID&
id = obj.uid().id;
1551 void* ptr = obj.m_data.empty() ? (
void*)
id : (
void*)&obj.m_data[0];
1552 if (!obj.m_data.empty())
1553 assert(type.size() == obj.m_data.size());
1554 if (type.isPrimitive() && !type.isPointer()) {
1555 if (type.isInteger() || type.isEnum()) {
1556 if (type.isSigned()) {
1557 if (type.size() == 1)
1558 value = (T)*(int8_t*)ptr;
1559 else if (type.size() == 2)
1560 value = (T)*(int16_t*)ptr;
1561 else if (type.size() == 4)
1562 value = (T)*(int32_t*)ptr;
1563 else if (type.size() == 8)
1564 value = (T)*(int64_t*)ptr;
1568 if (type.size() == 1)
1569 value = (T)*(uint8_t*)ptr;
1570 else if (type.size() == 2)
1571 value = (T)*(uint16_t*)ptr;
1572 else if (type.size() == 4)
1573 value = (T)*(uint32_t*)ptr;
1574 else if (type.size() == 8)
1575 value = (T)*(uint64_t*)ptr;
1579 }
else if (type.isReal()) {
1580 if (type.size() ==
sizeof(
float))
1581 value = (T)*(
float*)ptr;
1582 else if (type.size() ==
sizeof(double))
1583 value = (T)*(
double*)ptr;
1586 }
else if (type.isBool()) {
1587 value = (T)*(
bool*)ptr;
1588 }
else if (type.isString()) {
1589 value = _stringToNumber<T>(
1590 obj.m_data.empty() ? *(String*)ptr : String((
const char*)ptr)
1599 static String _encodePrimitiveValue(
const Object& obj) {
1600 return _encodeBlob( _primitiveObjectValueToString(obj) );
1603 static String _encode(
const Object& obj) {
1605 s += _encode(obj.type());
1606 s += _encodeBlob(ToString(obj.version()));
1607 s += _encodeBlob(ToString(obj.minVersion()));
1608 s += _encode(obj.uidChain());
1609 s += _encode(obj.members());
1610 s += _encodePrimitiveValue(obj);
1612 s += _encode(obj.parentUID());
1614 return _encodeBlob(s);
1617 String _encode(
const Archive::ObjectPool& objects) {
1619 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1620 itObject != objects.end(); ++itObject)
1622 const Object& obj = itObject->second;
1625 return _encodeBlob(s);
1642 #define MAGIC_START "Srx1v"
1643 #define ENCODING_FORMAT_MINOR_VERSION 2
1645 String Archive::_encodeRootBlob() {
1647 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1648 s += _encode(m_root);
1649 s += _encode(m_allObjects);
1650 s += _encodeBlob(m_name);
1651 s += _encodeBlob(m_comment);
1652 s += _encode(m_timeCreated);
1653 s += _encode(m_timeModified);
1654 return _encodeBlob(s);
1657 void Archive::encode() {
1659 String s = MAGIC_START;
1660 m_timeModified = time(NULL);
1661 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1662 m_timeCreated = m_timeModified;
1663 s += _encodeRootBlob();
1664 m_rawData.resize(s.length() + 1);
1665 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1666 m_isModified =
false;
1674 static _Blob _decodeBlob(
const char* p,
const char* end,
bool bThrow =
true) {
1675 if (!bThrow && p >= end) {
1676 const _Blob blob = { p, end };
1682 throw Exception(
"Decode Error: Missing blob");
1684 if (c ==
':')
break;
1685 if (c < '0' || c >
'9')
1686 throw Exception(
"Decode Error: Missing blob size");
1688 sz += size_t(c -
'0');
1692 throw Exception(
"Decode Error: Premature end of blob");
1693 const _Blob blob = { p, p + sz };
1697 template<
typename T_
int>
1698 static T_int _popIntBlob(
const char*& p,
const char* end) {
1699 _Blob blob = _decodeBlob(p, end);
1706 throw Exception(
"Decode Error: premature end of int blob");
1711 for (; p < end; ++p) {
1713 if (c < '0' || c >
'9')
1714 throw Exception(
"Decode Error: Invalid int blob format");
1716 i += size_t(c -
'0');
1721 template<
typename T_
int>
1722 static void _popIntBlob(
const char*& p,
const char* end,
RawData& rawData) {
1723 const T_int i = _popIntBlob<T_int>(p, end);
1724 *(T_int*)&rawData[0] = i;
1727 template<
typename T_real>
1728 static T_real _popRealBlob(
const char*& p,
const char* end) {
1729 _Blob blob = _decodeBlob(p, end);
1733 if (p >= end || (end - p) < 1)
1734 throw Exception(
"Decode Error: premature end of real blob");
1736 String s(p,
size_t(end - p));
1739 if (
sizeof(T_real) <=
sizeof(
double))
1740 r = atof(s.c_str());
1749 template<
typename T_real>
1750 static void _popRealBlob(
const char*& p,
const char* end,
RawData& rawData) {
1751 const T_real r = _popRealBlob<T_real>(p, end);
1752 *(T_real*)&rawData[0] = r;
1755 static String _popStringBlob(
const char*& p,
const char* end) {
1756 _Blob blob = _decodeBlob(p, end);
1760 throw Exception(
"Decode Error: missing String blob");
1762 const size_t sz = end - p;
1764 memcpy(&s[0], p, sz);
1769 static void _popStringBlob(
const char*& p,
const char* end,
RawData& rawData) {
1770 String s = _popStringBlob(p, end);
1771 rawData.resize(s.length() + 1);
1772 strcpy((
char*)&rawData[0], &s[0]);
1775 static time_t _popTimeBlob(
const char*& p,
const char* end) {
1776 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1780 static DataType _popDataTypeBlob(
const char*& p,
const char* end) {
1781 _Blob blob = _decodeBlob(p, end);
1788 type.m_baseTypeName = _popStringBlob(p, end);
1789 type.m_customTypeName = _popStringBlob(p, end);
1790 type.m_size = _popIntBlob<int>(p, end);
1791 type.m_isPointer = _popIntBlob<bool>(p, end);
1795 type.m_customTypeName2 = _popStringBlob(p, end);
1800 static UID _popUIDBlob(
const char*& p,
const char* end) {
1801 _Blob blob = _decodeBlob(p, end);
1806 throw Exception(
"Decode Error: premature end of UID blob");
1808 const ID id = (
ID) _popIntBlob<size_t>(p, end);
1809 const size_t size = _popIntBlob<size_t>(p, end);
1811 const UID uid = { id, size };
1815 static UIDChain _popUIDChainBlob(
const char*& p,
const char* end) {
1816 _Blob blob = _decodeBlob(p, end);
1822 const UID uid = _popUIDBlob(p, end);
1823 chain.push_back(uid);
1825 assert(!chain.empty());
1829 static Member _popMemberBlob(
const char*& p,
const char* end) {
1830 _Blob blob = _decodeBlob(p, end,
false);
1835 if (p >= end)
return m;
1837 m.m_uid = _popUIDBlob(p, end);
1838 m.m_offset = _popIntBlob<ssize_t>(p, end);
1839 m.m_name = _popStringBlob(p, end);
1840 m.m_type = _popDataTypeBlob(p, end);
1842 assert(!m.name().empty());
1843 assert(m.uid().isValid());
1847 static std::vector<Member> _popMembersBlob(
const char*& p,
const char* end) {
1848 _Blob blob = _decodeBlob(p, end,
false);
1852 std::vector<Member> members;
1854 const Member member = _popMemberBlob(p, end);
1856 members.push_back(member);
1863 static void _popPrimitiveValue(
const char*& p,
const char* end, Object& obj) {
1864 const DataType& type = obj.type();
1865 if (type.isPrimitive() && !type.isPointer()) {
1866 obj.m_data.resize(type.size());
1867 if (type.isInteger() || type.isEnum()) {
1868 if (type.isSigned()) {
1869 if (type.size() == 1)
1870 _popIntBlob<int8_t>(p, end, obj.m_data);
1871 else if (type.size() == 2)
1872 _popIntBlob<int16_t>(p, end, obj.m_data);
1873 else if (type.size() == 4)
1874 _popIntBlob<int32_t>(p, end, obj.m_data);
1875 else if (type.size() == 8)
1876 _popIntBlob<int64_t>(p, end, obj.m_data);
1880 if (type.size() == 1)
1881 _popIntBlob<uint8_t>(p, end, obj.m_data);
1882 else if (type.size() == 2)
1883 _popIntBlob<uint16_t>(p, end, obj.m_data);
1884 else if (type.size() == 4)
1885 _popIntBlob<uint32_t>(p, end, obj.m_data);
1886 else if (type.size() == 8)
1887 _popIntBlob<uint64_t>(p, end, obj.m_data);
1891 }
else if (type.isReal()) {
1892 if (type.size() ==
sizeof(
float))
1893 _popRealBlob<float>(p, end, obj.m_data);
1894 else if (type.size() ==
sizeof(
double))
1895 _popRealBlob<double>(p, end, obj.m_data);
1898 }
else if (type.isBool()) {
1899 _popIntBlob<uint8_t>(p, end, obj.m_data);
1900 }
else if (type.isString()) {
1901 _popStringBlob(p, end, obj.m_data);
1908 _Blob blob = _decodeBlob(p, end,
false);
1914 static Object _popObjectBlob(
const char*& p,
const char* end) {
1915 _Blob blob = _decodeBlob(p, end,
false);
1920 if (p >= end)
return obj;
1922 obj.m_type = _popDataTypeBlob(p, end);
1923 obj.m_version = _popIntBlob<Version>(p, end);
1924 obj.m_minVersion = _popIntBlob<Version>(p, end);
1925 obj.m_uid = _popUIDChainBlob(p, end);
1926 obj.m_members = _popMembersBlob(p, end);
1927 _popPrimitiveValue(p, end, obj);
1932 obj.m_parentUID = _popUIDBlob(p, end);
1937 void Archive::_popObjectsBlob(
const char*& p,
const char* end) {
1938 _Blob blob = _decodeBlob(p, end,
false);
1943 throw Exception(
"Decode Error: Premature end of objects blob");
1946 const Object obj = _popObjectBlob(p, end);
1948 m_allObjects[obj.uid()] = obj;
1952 void Archive::_popRootBlob(
const char*& p,
const char* end) {
1953 _Blob blob = _decodeBlob(p, end,
false);
1958 throw Exception(
"Decode Error: Premature end of root blob");
1962 const int formatMinorVersion = _popIntBlob<int>(p, end);
1964 m_root = _popUIDBlob(p, end);
1966 throw Exception(
"Decode Error: No root object");
1968 _popObjectsBlob(p, end);
1969 if (!m_allObjects[m_root])
1970 throw Exception(
"Decode Error: Missing declared root object");
1972 m_name = _popStringBlob(p, end);
1973 m_comment = _popStringBlob(p, end);
1974 m_timeCreated = _popTimeBlob(p, end);
1975 m_timeModified = _popTimeBlob(p, end);
1995 m_allObjects.clear();
1996 m_isModified =
false;
1997 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1998 const char* p = (
const char*) &data[0];
1999 const char* end = p + data.size();
2000 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
2001 throw Exception(
"Decode Error: Magic start missing!");
2002 p += strlen(MAGIC_START);
2003 _popRootBlob(p, end);
2029 memcpy(&
rawData[0], data, size);
2049 if (m_isModified) encode();
2077 return m_isModified;
2086 m_allObjects.clear();
2090 m_isModified =
false;
2091 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2115 if (m_name ==
name)
return;
2117 m_isModified =
true;
2141 if (m_comment ==
comment)
return;
2143 m_isModified =
true;
2146 static tm _convertTimeStamp(
const time_t& time,
time_base_t base) {
2150 pTm = localtime(&time);
2153 pTm = gmtime(&time);
2156 throw Exception(
"Time stamp with unknown time base (" + ToString((int64_t)base) +
") requested");
2159 throw Exception(
"Failed assembling time stamp structure");
2169 return m_timeCreated;
2178 return m_timeModified;
2192 return _convertTimeStamp(m_timeCreated, base);
2206 return _convertTimeStamp(m_timeModified, base);
2227 parent.remove(member);
2228 m_isModified =
true;
2248 if (!obj.
uid())
return;
2249 m_allObjects.erase(obj.
uid());
2250 m_isModified =
true;
2265 return m_allObjects[uid];
2286 return m_allObjects[member.
parentUID()];
2300 if (!
object)
return;
2301 object.setVersion(v);
2302 m_isModified =
true;
2316 if (!
object)
return;
2317 object.setMinVersion(v);
2318 m_isModified =
true;
2330 if (!
object)
return;
2331 if (!
object.type().isEnum())
2332 throw Exception(
"Not an enum data type");
2333 Object* pObject = &object;
2334 if (
object.type().isPointer()) {
2339 const int nativeEnumSize =
sizeof(
enum operation_t);
2343 if (type.
size() != nativeEnumSize) {
2344 type.m_size = nativeEnumSize;
2346 pObject->m_data.resize(type.
size());
2347 void* ptr = &pObject->m_data[0];
2348 if (type.
size() == 1)
2349 *(uint8_t*)ptr = (uint8_t)value;
2350 else if (type.
size() == 2)
2351 *(uint16_t*)ptr = (uint16_t)value;
2352 else if (type.
size() == 4)
2353 *(uint32_t*)ptr = (uint32_t)value;
2354 else if (type.
size() == 8)
2355 *(uint64_t*)ptr = (uint64_t)value;
2358 m_isModified =
true;
2372 if (!
object)
return;
2373 if (!
object.type().isInteger())
2374 throw Exception(
"Not an integer data type");
2375 Object* pObject = &object;
2376 if (
object.type().isPointer()) {
2382 pObject->m_data.resize(type.
size());
2383 void* ptr = &pObject->m_data[0];
2385 if (type.
size() == 1)
2386 *(int8_t*)ptr = (int8_t)value;
2387 else if (type.
size() == 2)
2388 *(int16_t*)ptr = (int16_t)value;
2389 else if (type.
size() == 4)
2390 *(int32_t*)ptr = (int32_t)value;
2391 else if (type.
size() == 8)
2392 *(int64_t*)ptr = (int64_t)value;
2396 if (type.
size() == 1)
2397 *(uint8_t*)ptr = (uint8_t)value;
2398 else if (type.
size() == 2)
2399 *(uint16_t*)ptr = (uint16_t)value;
2400 else if (type.
size() == 4)
2401 *(uint32_t*)ptr = (uint32_t)value;
2402 else if (type.
size() == 8)
2403 *(uint64_t*)ptr = (uint64_t)value;
2407 m_isModified =
true;
2422 if (!
object)
return;
2423 if (!
object.type().isReal())
2424 throw Exception(
"Not a real data type");
2425 Object* pObject = &object;
2426 if (
object.type().isPointer()) {
2432 pObject->m_data.resize(type.
size());
2433 void* ptr = &pObject->m_data[0];
2434 if (type.
size() ==
sizeof(
float))
2435 *(
float*)ptr = (
float)value;
2436 else if (type.
size() ==
sizeof(double))
2437 *(
double*)ptr = (
double)value;
2440 m_isModified =
true;
2452 if (!
object)
return;
2453 if (!
object.type().isBool())
2454 throw Exception(
"Not a bool data type");
2455 Object* pObject = &object;
2456 if (
object.type().isPointer()) {
2462 pObject->m_data.resize(type.
size());
2463 bool* ptr = (
bool*)&pObject->m_data[0];
2465 m_isModified =
true;
2477 if (!
object)
return;
2478 if (!
object.type().isString())
2479 throw Exception(
"Not a String data type");
2480 Object* pObject = &object;
2481 if (
object.type().isPointer()) {
2486 pObject->m_data.resize(value.length() + 1);
2487 char* ptr = (
char*) &pObject->m_data[0];
2488 strcpy(ptr, &value[0]);
2489 m_isModified =
true;
2506 if (!
object)
return;
2507 const DataType& type =
object.type();
2512 else if (type.
isBool()) {
2513 String val = toLowerCase(value);
2514 if (val ==
"true" || val ==
"yes" || val ==
"1")
2516 else if (val ==
"false" || val ==
"no" || val ==
"0")
2525 throw Exception(
"Not a primitive data type");
2540 if (
object.type().isClass())
2541 throw Exception(
"Object is class type");
2542 const Object* pObject = &object;
2543 if (
object.type().isPointer()) {
2545 if (!obj)
return "";
2548 return _primitiveObjectValueToString(*pObject);
2563 if (!
object.type().isInteger() && !
object.type().isEnum())
2564 throw Exception(
"Object is neither an integer nor an enum");
2565 const Object* pObject = &object;
2566 if (
object.type().isPointer()) {
2571 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2586 if (!
object.type().isReal())
2587 throw Exception(
"Object is not an real type");
2588 const Object* pObject = &object;
2589 if (
object.type().isPointer()) {
2594 return _primitiveObjectValueToNumber<double>(*pObject);
2608 if (!
object.type().isBool())
2609 throw Exception(
"Object is not a bool");
2610 const Object* pObject = &object;
2611 if (
object.type().isPointer()) {
2616 return _primitiveObjectValueToNumber<bool>(*pObject);
2626 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2627 : m_dst(dst), m_src(src)
2629 const Object srcRootObj = src.rootObject();
2630 const Object dstRootObj = dst.rootObject();
2632 throw Exception(
"No source root object!");
2634 throw Exception(
"Expected destination root object not found!");
2635 syncObject(dstRootObj, srcRootObj);
2638 void Archive::Syncer::syncPrimitive(
const Object& dstObj,
const Object& srcObj) {
2639 assert(srcObj.rawData().size() == dstObj.type().size());
2640 void* pDst = (
void*)dstObj.uid().id;
2641 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2644 void Archive::Syncer::syncString(
const Object& dstObj,
const Object& srcObj) {
2645 assert(dstObj.type().isString());
2646 assert(dstObj.type() == srcObj.type());
2647 String* pDst = (String*)(
void*)dstObj.uid().id;
2648 *pDst = (
String) (
const char*) &srcObj.rawData()[0];
2651 void Archive::Syncer::syncArray(
const Object& dstObj,
const Object& srcObj) {
2652 assert(dstObj.type().isArray());
2653 assert(dstObj.type() == srcObj.type());
2654 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2657 void Archive::Syncer::syncSet(
const Object& dstObj,
const Object& srcObj) {
2658 assert(dstObj.type().isSet());
2659 assert(dstObj.type() == srcObj.type());
2660 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2663 void Archive::Syncer::syncMap(
const Object& dstObj,
const Object& srcObj) {
2664 assert(dstObj.type().isMap());
2665 assert(dstObj.type() == srcObj.type());
2666 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2669 void Archive::Syncer::syncPointer(
const Object& dstObj,
const Object& srcObj) {
2670 assert(dstObj.type().isPointer());
2671 assert(dstObj.type() == srcObj.type());
2672 void** ppDst = (
void**)dstObj.uid().id;
2673 if (!srcObj.uid(1)) {
2677 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2678 std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2679 if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) {
2680 assert(uidRelation != m_counterparts.end());
2681 const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2682 assert(pointedDstObject);
2683 *ppDst = (
void*)pointedDstObject.uid().id;
2685 assert(pointedSrcObject.type());
2686 Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2687 assert(pointedDstObject);
2689 m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2690 *ppDst = (
void*)pointedDstObject.uid().id;
2691 syncObject(pointedDstObject, pointedSrcObject);
2695 void Archive::Syncer::syncObject(
const Object& dstObj,
const Object& srcObj) {
2696 assert(dstObj && srcObj);
2706 const bool alreadySynced =
2707 !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2714 if (!dstObj.isVersionCompatibleTo(srcObj))
2715 throw Exception(
"Version incompatible (destination version " +
2716 ToString(dstObj.version()) +
" [min. version " +
2717 ToString(dstObj.minVersion()) +
"], source version " +
2718 ToString(srcObj.version()) +
" [min. version " +
2719 ToString(srcObj.minVersion()) +
"])");
2720 if (dstObj.type() != srcObj.type())
2721 throw Exception(
"Incompatible data structure type (destination type " +
2722 dstObj.type().asLongDescr() +
" vs. source type " +
2723 srcObj.type().asLongDescr() +
")");
2725 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2726 if (dstObj.type().isString())
2727 syncString(dstObj, srcObj);
2729 syncPrimitive(dstObj, srcObj);
2733 if (dstObj.type().isArray()) {
2734 syncArray(dstObj, srcObj);
2738 if (dstObj.type().isSet()) {
2739 syncSet(dstObj, srcObj);
2743 if (dstObj.type().isMap()) {
2744 syncMap(dstObj, srcObj);
2748 if (dstObj.type().isPointer()) {
2749 syncPointer(dstObj, srcObj);
2753 assert(dstObj.type().isClass());
2754 for (
int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2755 const Member& srcMember = srcObj.members()[iMember];
2756 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2758 throw Exception(
"Expected member missing in destination object");
2759 syncMember(dstMember, srcMember);
2763 Member Archive::Syncer::dstMemberMatching(
const Object& dstObj,
const Object& srcObj,
const Member& srcMember) {
2764 Member dstMember = dstObj.memberNamed(srcMember.name());
2766 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2767 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2768 if (members.size() <= 0)
2770 if (members.size() == 1)
2772 for (
int i = 0; i < members.size(); ++i)
2773 if (members[i].offset() == srcMember.offset())
2775 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2776 assert(srcSeqNr >= 0);
2777 for (
int i = 0; i < members.size(); ++i) {
2778 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2779 if (dstSeqNr == srcSeqNr)
2785 void Archive::Syncer::syncMember(
const Member& dstMember,
const Member& srcMember) {
2786 assert(dstMember && srcMember);
2787 assert(dstMember.type() == srcMember.type());
2788 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2789 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2790 syncObject(dstObj, srcObj);
2796 Exception::Exception() {
2799 Exception::Exception(String format, ...) {
2801 va_start(arg, format);
2802 Message = assemble(format, arg);
2806 Exception::Exception(String format, va_list arg) {
2807 Message = assemble(format, arg);
2816 std::cout <<
"Serialization::Exception: " << Message << std::endl;
2819 String Exception::assemble(
String format, va_list arg) {
2821 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.
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...