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;
115 String customType1, String customType2)
119 m_baseTypeName = baseType;
120 m_customTypeName = customType1;
121 m_customTypeName2 = customType2;
173 return m_baseTypeName ==
"class";
211 return m_baseTypeName ==
"String";
229 return m_baseTypeName.substr(0, 3) ==
"int" ||
230 m_baseTypeName.substr(0, 4) ==
"uint";
246 return m_baseTypeName.substr(0, 4) ==
"real";
261 return m_baseTypeName ==
"bool";
276 return m_baseTypeName ==
"enum";
292 return m_baseTypeName ==
"Array";
308 return m_baseTypeName ==
"Set";
324 return m_baseTypeName ==
"Map";
341 return m_baseTypeName.substr(0, 3) ==
"int" ||
364 return m_baseTypeName == other.m_baseTypeName &&
365 m_customTypeName == other.m_customTypeName &&
366 m_customTypeName2 == other.m_customTypeName2 &&
368 m_isPointer == other.m_isPointer;
392 return m_baseTypeName < other.m_baseTypeName ||
393 (m_baseTypeName == other.m_baseTypeName &&
394 (m_customTypeName < other.m_customTypeName ||
395 (m_customTypeName == other.m_customTypeName &&
396 (m_customTypeName2 < other.m_customTypeName2 ||
397 (m_customTypeName2 == other.m_customTypeName2 &&
398 (m_size < other.m_size ||
399 (m_size == other.m_size &&
400 m_isPointer < other.m_isPointer)))))));
433 String s = m_baseTypeName;
434 if (!m_customTypeName.empty())
436 if (!m_customTypeName2.empty())
473 return m_baseTypeName;
476 static String _demangleTypeName(
const char* name) {
478 const size_t MAXLENGTH = 1024;
479 char result[MAXLENGTH];
483 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
492 abi::__cxa_demangle(name, 0, 0, &status);
493 String sResult = result;
495 return (status == 0) ? sResult : name;
536 if (!demangle)
return m_customTypeName;
537 return _demangleTypeName(m_customTypeName.c_str());
548 if (!demangle)
return m_customTypeName2;
549 return _demangleTypeName(m_customTypeName2.c_str());
685 return m_uid && !m_name.empty() && m_type;
697 return m_uid == other.m_uid &&
698 m_offset == other.m_offset &&
699 m_name == other.m_name &&
700 m_type == other.m_type;
725 return m_uid < other.m_uid ||
726 (m_uid == other.m_uid &&
727 (m_offset < other.m_offset ||
728 (m_offset == other.m_offset &&
729 (m_name < other.m_name ||
730 (m_name == other.m_name &&
731 m_type < other.m_type)))));
805 return m_type && !m_uid.empty();
820 return (index < m_uid.size()) ? m_uid[index] :
NO_UID;
823 static void _setNativeValueFromString(
void* ptr,
const DataType& type,
const char* s) {
827 if (type.
size() == 1)
828 *(int8_t*)ptr = (int8_t) atoll(s);
829 else if (type.
size() == 2)
830 *(int16_t*)ptr = (int16_t) atoll(s);
831 else if (type.
size() == 4)
832 *(int32_t*)ptr = (int32_t) atoll(s);
833 else if (type.
size() == 8)
834 *(int64_t*)ptr = (int64_t) atoll(s);
838 if (type.
size() == 1)
839 *(uint8_t*)ptr = (uint8_t) atoll(s);
840 else if (type.
size() == 2)
841 *(uint16_t*)ptr = (uint16_t) atoll(s);
842 else if (type.
size() == 4)
843 *(uint32_t*)ptr = (uint32_t) atoll(s);
844 else if (type.
size() == 8)
845 *(uint64_t*)ptr = (uint64_t) atoll(s);
849 }
else if (type.
isReal()) {
850 if (type.
size() ==
sizeof(
float))
851 *(
float*)ptr = (
float) atof(s);
852 else if (type.
size() ==
sizeof(
double))
853 *(
double*)ptr = (
double) atof(s);
856 }
else if (type.
isBool()) {
857 String lower = toLowerCase(s);
858 const bool b = lower !=
"0" && lower !=
"false" && lower !=
"no";
885 void* ptr = (
void*)
id;
886 _setNativeValueFromString(ptr, m_type, s.c_str());
1022 return m_uid == other.m_uid &&
1023 m_type == other.m_type;
1050 return m_uid < other.m_uid ||
1051 (m_uid == other.m_uid &&
1052 m_type < other.m_type);
1098 void Object::setVersion(
Version v) {
1102 void Object::setMinVersion(
Version v) {
1136 for (
int i = 0; i < m_members.size(); ++i)
1137 if (m_members[i].name() == name)
1138 return m_members[i];
1158 for (
int i = 0; i < m_members.size(); ++i)
1159 if (m_members[i].
uid() ==
uid)
1160 return m_members[i];
1164 void Object::remove(
const Member& member) {
1165 for (
int i = 0; i < m_members.size(); ++i) {
1166 if (m_members[i] == member) {
1167 m_members.erase(m_members.begin() + i);
1189 std::vector<Member> v;
1190 for (
int i = 0; i < m_members.size(); ++i) {
1191 const Member& member = m_members[i];
1193 v.push_back(member);
1230 for (
int i = 0; i < m_members.size(); ++i)
1231 if (m_members[i] == member)
1260 m_isModified =
false;
1261 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1282 m_isModified =
false;
1283 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1310 m_isModified =
false;
1311 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1315 Archive::~Archive() {
1329 return m_allObjects[m_root];
1332 static String _encodeBlob(String data) {
1333 return ToString(data.length()) +
":" + data;
1336 static String _encode(
const UID& uid) {
1338 s += _encodeBlob(ToString(
size_t(uid.id)));
1339 s += _encodeBlob(ToString(
size_t(uid.size)));
1340 return _encodeBlob(s);
1343 static String _encode(
const time_t& time) {
1344 return _encodeBlob(ToString(time));
1347 static String _encode(
const DataType& type) {
1351 s += _encodeBlob(type.baseTypeName());
1352 s += _encodeBlob(type.customTypeName());
1353 s += _encodeBlob(ToString(type.size()));
1354 s += _encodeBlob(ToString(type.isPointer()));
1357 s += _encodeBlob(type.customTypeName2());
1359 return _encodeBlob(s);
1364 for (
int i = 0; i < chain.size(); ++i)
1365 s += _encode(chain[i]);
1366 return _encodeBlob(s);
1369 static String _encode(
const Member& member) {
1371 s += _encode(member.uid());
1372 s += _encodeBlob(ToString(member.offset()));
1373 s += _encodeBlob(member.name());
1374 s += _encode(member.type());
1375 return _encodeBlob(s);
1378 static String _encode(
const std::vector<Member>& members) {
1380 for (
int i = 0; i < members.size(); ++i)
1381 s += _encode(members[i]);
1382 return _encodeBlob(s);
1385 static String _primitiveObjectValueToString(
const Object& obj) {
1387 const DataType& type = obj.type();
1388 const ID&
id = obj.uid().id;
1389 void* ptr = obj.m_data.empty() ? (
void*)
id : (void*)&obj.m_data[0];
1390 if (!obj.m_data.empty())
1391 assert(type.size() == obj.m_data.size());
1392 if (type.isPrimitive() && !type.isPointer()) {
1393 if (type.isInteger() || type.isEnum()) {
1394 if (type.isSigned()) {
1395 if (type.size() == 1)
1396 s = ToString((int16_t)*(int8_t*)ptr);
1397 else if (type.size() == 2)
1398 s = ToString(*(int16_t*)ptr);
1399 else if (type.size() == 4)
1400 s = ToString(*(int32_t*)ptr);
1401 else if (type.size() == 8)
1402 s = ToString(*(int64_t*)ptr);
1406 if (type.size() == 1)
1407 s = ToString((uint16_t)*(uint8_t*)ptr);
1408 else if (type.size() == 2)
1409 s = ToString(*(uint16_t*)ptr);
1410 else if (type.size() == 4)
1411 s = ToString(*(uint32_t*)ptr);
1412 else if (type.size() == 8)
1413 s = ToString(*(uint64_t*)ptr);
1417 }
else if (type.isReal()) {
1418 if (type.size() == sizeof(float))
1419 s = ToString(*(float*)ptr);
1420 else if (type.size() == sizeof(double))
1421 s = ToString(*(double*)ptr);
1424 }
else if (type.isBool()) {
1425 s = ToString(*(bool*)ptr);
1426 }
else if (type.isString()) {
1427 s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1435 template<
typename T>
1436 inline T _stringToNumber(
const String& s) {
1441 inline int64_t _stringToNumber(
const String& s) {
1442 return atoll(s.c_str());
1446 inline double _stringToNumber(
const String& s) {
1447 return atof(s.c_str());
1451 inline bool _stringToNumber(
const String& s) {
1452 return (
bool) atoll(s.c_str());
1455 template<
typename T>
1456 static T _primitiveObjectValueToNumber(
const Object& obj) {
1458 const DataType& type = obj.type();
1459 const ID&
id = obj.uid().id;
1460 void* ptr = obj.m_data.empty() ? (
void*)
id : (void*)&obj.m_data[0];
1461 if (!obj.m_data.empty())
1462 assert(type.size() == obj.m_data.size());
1463 if (type.isPrimitive() && !type.isPointer()) {
1464 if (type.isInteger() || type.isEnum()) {
1465 if (type.isSigned()) {
1466 if (type.size() == 1)
1467 value = (T)*(int8_t*)ptr;
1468 else if (type.size() == 2)
1469 value = (T)*(int16_t*)ptr;
1470 else if (type.size() == 4)
1471 value = (T)*(int32_t*)ptr;
1472 else if (type.size() == 8)
1473 value = (T)*(int64_t*)ptr;
1477 if (type.size() == 1)
1478 value = (T)*(uint8_t*)ptr;
1479 else if (type.size() == 2)
1480 value = (T)*(uint16_t*)ptr;
1481 else if (type.size() == 4)
1482 value = (T)*(uint32_t*)ptr;
1483 else if (type.size() == 8)
1484 value = (T)*(uint64_t*)ptr;
1488 }
else if (type.isReal()) {
1489 if (type.size() == sizeof(float))
1490 value = (T)*(float*)ptr;
1491 else if (type.size() == sizeof(double))
1492 value = (T)*(double*)ptr;
1495 }
else if (type.isBool()) {
1496 value = (T)*(bool*)ptr;
1497 }
else if (type.isString()) {
1498 value = _stringToNumber<T>(
1499 obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1508 static String _encodePrimitiveValue(
const Object& obj) {
1509 return _encodeBlob( _primitiveObjectValueToString(obj) );
1512 static String _encode(
const Object& obj) {
1514 s += _encode(obj.type());
1515 s += _encodeBlob(ToString(obj.version()));
1516 s += _encodeBlob(ToString(obj.minVersion()));
1517 s += _encode(obj.uidChain());
1518 s += _encode(obj.members());
1519 s += _encodePrimitiveValue(obj);
1520 return _encodeBlob(s);
1523 String _encode(
const Archive::ObjectPool& objects) {
1525 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1526 itObject != objects.end(); ++itObject)
1528 const Object& obj = itObject->second;
1531 return _encodeBlob(s);
1541 #define MAGIC_START "Srx1v"
1542 #define ENCODING_FORMAT_MINOR_VERSION 1
1544 String Archive::_encodeRootBlob() {
1546 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1547 s += _encode(m_root);
1548 s += _encode(m_allObjects);
1549 s += _encodeBlob(m_name);
1550 s += _encodeBlob(m_comment);
1551 s += _encode(m_timeCreated);
1552 s += _encode(m_timeModified);
1553 return _encodeBlob(s);
1556 void Archive::encode() {
1559 m_timeModified = time(NULL);
1560 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1561 m_timeCreated = m_timeModified;
1562 s += _encodeRootBlob();
1563 m_rawData.resize(s.length() + 1);
1564 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1565 m_isModified =
false;
1573 static _Blob _decodeBlob(
const char* p,
const char* end,
bool bThrow =
true) {
1574 if (!bThrow && p >= end) {
1575 const _Blob blob = { p, end };
1581 throw Exception(
"Decode Error: Missing blob");
1583 if (c ==
':')
break;
1584 if (c <
'0' || c >
'9')
1585 throw Exception(
"Decode Error: Missing blob size");
1587 sz += size_t(c -
'0');
1591 throw Exception(
"Decode Error: Premature end of blob");
1592 const _Blob blob = { p, p + sz };
1596 template<
typename T_
int>
1597 static T_int _popIntBlob(
const char*& p,
const char* end) {
1598 _Blob blob = _decodeBlob(p, end);
1605 throw Exception(
"Decode Error: premature end of int blob");
1610 for (; p < end; ++p) {
1612 if (c <
'0' || c >
'9')
1613 throw Exception(
"Decode Error: Invalid int blob format");
1615 i += size_t(c -
'0');
1620 template<
typename T_
int>
1621 static void _popIntBlob(
const char*& p,
const char* end, RawData& rawData) {
1622 const T_int i = _popIntBlob<T_int>(p, end);
1623 *(T_int*)&rawData[0] = i;
1626 template<
typename T_real>
1627 static T_real _popRealBlob(
const char*& p,
const char* end) {
1628 _Blob blob = _decodeBlob(p, end);
1632 if (p >= end || (end - p) < 1)
1633 throw Exception(
"Decode Error: premature end of real blob");
1635 String s(p,
size_t(end - p));
1638 if (
sizeof(T_real) <=
sizeof(
double))
1639 r = atof(s.c_str());
1648 template<
typename T_real>
1649 static void _popRealBlob(
const char*& p,
const char* end, RawData& rawData) {
1650 const T_real r = _popRealBlob<T_real>(p, end);
1651 *(T_real*)&rawData[0] = r;
1654 static String _popStringBlob(
const char*& p,
const char* end) {
1655 _Blob blob = _decodeBlob(p, end);
1659 throw Exception(
"Decode Error: missing String blob");
1661 const size_t sz = end - p;
1663 memcpy(&s[0], p, sz);
1668 static void _popStringBlob(
const char*& p,
const char* end, RawData& rawData) {
1669 String s = _popStringBlob(p, end);
1670 rawData.resize(s.length() + 1);
1671 strcpy((
char*)&rawData[0], &s[0]);
1674 static time_t _popTimeBlob(
const char*& p,
const char* end) {
1675 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1679 static DataType _popDataTypeBlob(
const char*& p,
const char* end) {
1680 _Blob blob = _decodeBlob(p, end);
1687 type.m_baseTypeName = _popStringBlob(p, end);
1688 type.m_customTypeName = _popStringBlob(p, end);
1689 type.m_size = _popIntBlob<int>(p, end);
1690 type.m_isPointer = _popIntBlob<bool>(p, end);
1694 type.m_customTypeName2 = _popStringBlob(p, end);
1699 static UID _popUIDBlob(
const char*& p,
const char* end) {
1700 _Blob blob = _decodeBlob(p, end);
1705 throw Exception(
"Decode Error: premature end of UID blob");
1707 const ID id = (
ID) _popIntBlob<size_t>(p, end);
1708 const size_t size = _popIntBlob<size_t>(p, end);
1710 const UID uid = { id, size };
1714 static UIDChain _popUIDChainBlob(
const char*& p,
const char* end) {
1715 _Blob blob = _decodeBlob(p, end);
1721 const UID uid = _popUIDBlob(p, end);
1722 chain.push_back(uid);
1724 assert(!chain.empty());
1728 static Member _popMemberBlob(
const char*& p,
const char* end) {
1729 _Blob blob = _decodeBlob(p, end,
false);
1734 if (p >= end)
return m;
1736 m.m_uid = _popUIDBlob(p, end);
1737 m.m_offset = _popIntBlob<ssize_t>(p, end);
1738 m.m_name = _popStringBlob(p, end);
1739 m.m_type = _popDataTypeBlob(p, end);
1741 assert(!m.name().empty());
1742 assert(m.uid().isValid());
1746 static std::vector<Member> _popMembersBlob(
const char*& p,
const char* end) {
1747 _Blob blob = _decodeBlob(p, end,
false);
1751 std::vector<Member> members;
1753 const Member member = _popMemberBlob(p, end);
1755 members.push_back(member);
1762 static void _popPrimitiveValue(
const char*& p,
const char* end, Object& obj) {
1763 const DataType& type = obj.type();
1764 if (type.isPrimitive() && !type.isPointer()) {
1765 obj.m_data.resize(type.size());
1766 if (type.isInteger() || type.isEnum()) {
1767 if (type.isSigned()) {
1768 if (type.size() == 1)
1769 _popIntBlob<int8_t>(p, end, obj.m_data);
1770 else if (type.size() == 2)
1771 _popIntBlob<int16_t>(p, end, obj.m_data);
1772 else if (type.size() == 4)
1773 _popIntBlob<int32_t>(p, end, obj.m_data);
1774 else if (type.size() == 8)
1775 _popIntBlob<int64_t>(p, end, obj.m_data);
1779 if (type.size() == 1)
1780 _popIntBlob<uint8_t>(p, end, obj.m_data);
1781 else if (type.size() == 2)
1782 _popIntBlob<uint16_t>(p, end, obj.m_data);
1783 else if (type.size() == 4)
1784 _popIntBlob<uint32_t>(p, end, obj.m_data);
1785 else if (type.size() == 8)
1786 _popIntBlob<uint64_t>(p, end, obj.m_data);
1790 }
else if (type.isReal()) {
1791 if (type.size() ==
sizeof(
float))
1792 _popRealBlob<float>(p, end, obj.m_data);
1793 else if (type.size() ==
sizeof(
double))
1794 _popRealBlob<double>(p, end, obj.m_data);
1797 }
else if (type.isBool()) {
1798 _popIntBlob<uint8_t>(p, end, obj.m_data);
1799 }
else if (type.isString()) {
1800 _popStringBlob(p, end, obj.m_data);
1807 _Blob blob = _decodeBlob(p, end,
false);
1813 static Object _popObjectBlob(
const char*& p,
const char* end) {
1814 _Blob blob = _decodeBlob(p, end,
false);
1819 if (p >= end)
return obj;
1821 obj.m_type = _popDataTypeBlob(p, end);
1822 obj.m_version = _popIntBlob<Version>(p, end);
1823 obj.m_minVersion = _popIntBlob<Version>(p, end);
1824 obj.m_uid = _popUIDChainBlob(p, end);
1825 obj.m_members = _popMembersBlob(p, end);
1826 _popPrimitiveValue(p, end, obj);
1831 void Archive::_popObjectsBlob(
const char*& p,
const char* end) {
1832 _Blob blob = _decodeBlob(p, end,
false);
1837 throw Exception(
"Decode Error: Premature end of objects blob");
1840 const Object obj = _popObjectBlob(p, end);
1842 m_allObjects[obj.uid()] = obj;
1846 void Archive::_popRootBlob(
const char*& p,
const char* end) {
1847 _Blob blob = _decodeBlob(p, end,
false);
1852 throw Exception(
"Decode Error: Premature end of root blob");
1856 const int formatMinorVersion = _popIntBlob<int>(p, end);
1858 m_root = _popUIDBlob(p, end);
1860 throw Exception(
"Decode Error: No root object");
1862 _popObjectsBlob(p, end);
1863 if (!m_allObjects[m_root])
1864 throw Exception(
"Decode Error: Missing declared root object");
1866 m_name = _popStringBlob(p, end);
1867 m_comment = _popStringBlob(p, end);
1868 m_timeCreated = _popTimeBlob(p, end);
1869 m_timeModified = _popTimeBlob(p, end);
1889 m_allObjects.clear();
1890 m_isModified =
false;
1891 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1892 const char* p = (
const char*) &data[0];
1893 const char* end = p + data.size();
1894 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
1895 throw Exception(
"Decode Error: Magic start missing!");
1896 p += strlen(MAGIC_START);
1897 _popRootBlob(p, end);
1920 void Archive::decode(
const uint8_t* data,
size_t size) {
1922 rawData.resize(size);
1923 memcpy(&rawData[0], data, size);
1943 if (m_isModified) encode();
1952 String Archive::rawDataFormat()
const {
1970 bool Archive::isModified()
const {
1971 return m_isModified;
1979 void Archive::clear() {
1980 m_allObjects.clear();
1981 m_operation = OPERATION_NONE;
1984 m_isModified =
false;
1985 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1995 String Archive::name()
const {
2008 void Archive::setName(String name) {
2009 if (m_name == name)
return;
2011 m_isModified =
true;
2021 String Archive::comment()
const {
2034 void Archive::setComment(String comment) {
2035 if (m_comment == comment)
return;
2036 m_comment = comment;
2037 m_isModified =
true;
2040 static tm _convertTimeStamp(
const time_t& time,
time_base_t base) {
2044 pTm = localtime(&time);
2047 pTm = gmtime(&time);
2050 throw Exception(
"Time stamp with unknown time base (" + ToString((int64_t)base) +
") requested");
2053 throw Exception(
"Failed assembling time stamp structure");
2062 time_t Archive::timeStampCreated()
const {
2063 return m_timeCreated;
2071 time_t Archive::timeStampModified()
const {
2072 return m_timeModified;
2086 return _convertTimeStamp(m_timeCreated, base);
2100 return _convertTimeStamp(m_timeModified, base);
2121 parent.remove(member);
2122 m_isModified =
true;
2142 if (!obj.
uid())
return;
2143 m_allObjects.erase(obj.
uid());
2144 m_isModified =
true;
2159 return m_allObjects[uid];
2173 if (!
object)
return;
2174 object.setVersion(v);
2175 m_isModified =
true;
2189 if (!
object)
return;
2190 object.setMinVersion(v);
2191 m_isModified =
true;
2202 void Archive::setEnumValue(
Object&
object, uint64_t value) {
2203 if (!
object)
return;
2204 if (!
object.type().isEnum())
2205 throw Exception(
"Not an enum data type");
2206 Object* pObject = &object;
2207 if (
object.type().isPointer()) {
2208 Object& obj = objectByUID(
object.uid(1));
2212 const int nativeEnumSize =
sizeof(
enum operation_t);
2216 if (type.
size() != nativeEnumSize) {
2217 type.m_size = nativeEnumSize;
2219 pObject->m_data.resize(type.
size());
2220 void* ptr = &pObject->m_data[0];
2221 if (type.
size() == 1)
2222 *(uint8_t*)ptr = (uint8_t)value;
2223 else if (type.
size() == 2)
2224 *(uint16_t*)ptr = (uint16_t)value;
2225 else if (type.
size() == 4)
2226 *(uint32_t*)ptr = (uint32_t)value;
2227 else if (type.
size() == 8)
2228 *(uint64_t*)ptr = (uint64_t)value;
2231 m_isModified =
true;
2244 void Archive::setIntValue(
Object&
object, int64_t value) {
2245 if (!
object)
return;
2246 if (!
object.type().isInteger())
2247 throw Exception(
"Not an integer data type");
2248 Object* pObject = &object;
2249 if (
object.type().isPointer()) {
2250 Object& obj = objectByUID(
object.uid(1));
2255 pObject->m_data.resize(type.
size());
2256 void* ptr = &pObject->m_data[0];
2258 if (type.
size() == 1)
2259 *(int8_t*)ptr = (int8_t)value;
2260 else if (type.
size() == 2)
2261 *(int16_t*)ptr = (int16_t)value;
2262 else if (type.
size() == 4)
2263 *(int32_t*)ptr = (int32_t)value;
2264 else if (type.
size() == 8)
2265 *(int64_t*)ptr = (int64_t)value;
2269 if (type.
size() == 1)
2270 *(uint8_t*)ptr = (uint8_t)value;
2271 else if (type.
size() == 2)
2272 *(uint16_t*)ptr = (uint16_t)value;
2273 else if (type.
size() == 4)
2274 *(uint32_t*)ptr = (uint32_t)value;
2275 else if (type.
size() == 8)
2276 *(uint64_t*)ptr = (uint64_t)value;
2280 m_isModified =
true;
2294 void Archive::setRealValue(
Object&
object,
double value) {
2295 if (!
object)
return;
2296 if (!
object.type().isReal())
2297 throw Exception(
"Not a real data type");
2298 Object* pObject = &object;
2299 if (
object.type().isPointer()) {
2300 Object& obj = objectByUID(
object.uid(1));
2305 pObject->m_data.resize(type.
size());
2306 void* ptr = &pObject->m_data[0];
2307 if (type.
size() ==
sizeof(
float))
2308 *(
float*)ptr = (
float)value;
2309 else if (type.
size() ==
sizeof(
double))
2310 *(
double*)ptr = (
double)value;
2313 m_isModified =
true;
2324 void Archive::setBoolValue(
Object&
object,
bool value) {
2325 if (!
object)
return;
2326 if (!
object.type().isBool())
2327 throw Exception(
"Not a bool data type");
2328 Object* pObject = &object;
2329 if (
object.type().isPointer()) {
2330 Object& obj = objectByUID(
object.uid(1));
2335 pObject->m_data.resize(type.
size());
2336 bool* ptr = (
bool*)&pObject->m_data[0];
2338 m_isModified =
true;
2349 void Archive::setStringValue(
Object&
object, String value) {
2350 if (!
object)
return;
2351 if (!
object.type().isString())
2352 throw Exception(
"Not a String data type");
2353 Object* pObject = &object;
2354 if (
object.type().isPointer()) {
2355 Object& obj = objectByUID(
object.uid(1));
2359 pObject->m_data.resize(value.length() + 1);
2360 char* ptr = (
char*) &pObject->m_data[0];
2361 strcpy(ptr, &value[0]);
2362 m_isModified =
true;
2378 void Archive::setAutoValue(
Object&
object, String value) {
2379 if (!
object)
return;
2380 const DataType& type =
object.type();
2382 setIntValue(
object, atoll(value.c_str()));
2384 setRealValue(
object, atof(value.c_str()));
2385 else if (type.
isBool()) {
2386 String val = toLowerCase(value);
2387 if (val ==
"true" || val ==
"yes" || val ==
"1")
2388 setBoolValue(
object,
true);
2389 else if (val ==
"false" || val ==
"no" || val ==
"0")
2390 setBoolValue(
object,
false);
2392 setBoolValue(
object, atof(value.c_str()));
2394 setStringValue(
object, value);
2396 setEnumValue(
object, atoll(value.c_str()));
2398 throw Exception(
"Not a primitive data type");
2410 String Archive::valueAsString(
const Object&
object) {
2413 if (
object.type().isClass())
2414 throw Exception(
"Object is class type");
2415 const Object* pObject = &object;
2416 if (
object.type().isPointer()) {
2417 const Object& obj = objectByUID(
object.uid(1));
2418 if (!obj)
return "";
2421 return _primitiveObjectValueToString(*pObject);
2433 int64_t Archive::valueAsInt(
const Object&
object) {
2436 if (!
object.type().isInteger() && !
object.type().isEnum())
2437 throw Exception(
"Object is neither an integer nor an enum");
2438 const Object* pObject = &object;
2439 if (
object.type().isPointer()) {
2440 const Object& obj = objectByUID(
object.uid(1));
2444 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2456 double Archive::valueAsReal(
const Object&
object) {
2459 if (!
object.type().isReal())
2460 throw Exception(
"Object is not an real type");
2461 const Object* pObject = &object;
2462 if (
object.type().isPointer()) {
2463 const Object& obj = objectByUID(
object.uid(1));
2467 return _primitiveObjectValueToNumber<double>(*pObject);
2478 bool Archive::valueAsBool(
const Object&
object) {
2481 if (!
object.type().isBool())
2482 throw Exception(
"Object is not a bool");
2483 const Object* pObject = &object;
2484 if (
object.type().isPointer()) {
2485 const Object& obj = objectByUID(
object.uid(1));
2489 return _primitiveObjectValueToNumber<bool>(*pObject);
2499 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2500 : m_dst(dst), m_src(src)
2502 const Object srcRootObj = src.rootObject();
2503 const Object dstRootObj = dst.rootObject();
2505 throw Exception(
"No source root object!");
2507 throw Exception(
"Expected destination root object not found!");
2508 syncObject(dstRootObj, srcRootObj);
2511 void Archive::Syncer::syncPrimitive(
const Object& dstObj,
const Object& srcObj) {
2512 assert(srcObj.rawData().size() == dstObj.type().size());
2513 void* pDst = (
void*)dstObj.uid().id;
2514 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2517 void Archive::Syncer::syncString(
const Object& dstObj,
const Object& srcObj) {
2518 assert(dstObj.type().isString());
2519 assert(dstObj.type() == srcObj.type());
2521 *pDst = (
String) (
const char*) &srcObj.rawData()[0];
2524 void Archive::Syncer::syncArray(
const Object& dstObj,
const Object& srcObj) {
2525 assert(dstObj.type().isArray());
2526 assert(dstObj.type() == srcObj.type());
2527 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2530 void Archive::Syncer::syncSet(
const Object& dstObj,
const Object& srcObj) {
2531 assert(dstObj.type().isSet());
2532 assert(dstObj.type() == srcObj.type());
2533 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2536 void Archive::Syncer::syncMap(
const Object& dstObj,
const Object& srcObj) {
2537 assert(dstObj.type().isMap());
2538 assert(dstObj.type() == srcObj.type());
2539 dstObj.m_sync(
const_cast<Object&
>(dstObj), srcObj,
this);
2542 void Archive::Syncer::syncPointer(
const Object& dstObj,
const Object& srcObj) {
2543 assert(dstObj.type().isPointer());
2544 assert(dstObj.type() == srcObj.type());
2545 const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
2546 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2547 syncObject(pointedDstObject, pointedSrcObject);
2550 void Archive::Syncer::syncObject(
const Object& dstObj,
const Object& srcObj) {
2551 if (!dstObj || !srcObj)
return;
2552 if (!dstObj.isVersionCompatibleTo(srcObj))
2553 throw Exception(
"Version incompatible (destination version " +
2554 ToString(dstObj.version()) +
" [min. version " +
2555 ToString(dstObj.minVersion()) +
"], source version " +
2556 ToString(srcObj.version()) +
" [min. version " +
2557 ToString(srcObj.minVersion()) +
"])");
2558 if (dstObj.type() != srcObj.type())
2559 throw Exception(
"Incompatible data structure type (destination type " +
2560 dstObj.type().asLongDescr() +
" vs. source type " +
2561 srcObj.type().asLongDescr() +
")");
2565 m_dst.m_allObjects.erase(dstObj.uid());
2567 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2568 if (dstObj.type().isString())
2569 syncString(dstObj, srcObj);
2571 syncPrimitive(dstObj, srcObj);
2575 if (dstObj.type().isArray()) {
2576 syncArray(dstObj, srcObj);
2580 if (dstObj.type().isSet()) {
2581 syncSet(dstObj, srcObj);
2585 if (dstObj.type().isMap()) {
2586 syncMap(dstObj, srcObj);
2590 if (dstObj.type().isPointer()) {
2591 syncPointer(dstObj, srcObj);
2595 assert(dstObj.type().isClass());
2596 for (
int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2597 const Member& srcMember = srcObj.members()[iMember];
2598 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2600 throw Exception(
"Expected member missing in destination object");
2601 syncMember(dstMember, srcMember);
2605 Member Archive::Syncer::dstMemberMatching(
const Object& dstObj,
const Object& srcObj,
const Member& srcMember) {
2606 Member dstMember = dstObj.memberNamed(srcMember.name());
2608 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2609 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2610 if (members.size() <= 0)
2612 if (members.size() == 1)
2614 for (
int i = 0; i < members.size(); ++i)
2615 if (members[i].offset() == srcMember.offset())
2617 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2618 assert(srcSeqNr >= 0);
2619 for (
int i = 0; i < members.size(); ++i) {
2620 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2621 if (dstSeqNr == srcSeqNr)
2627 void Archive::Syncer::syncMember(
const Member& dstMember,
const Member& srcMember) {
2628 assert(dstMember && srcMember);
2629 assert(dstMember.type() == srcMember.type());
2630 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2631 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2632 syncObject(dstObj, srcObj);
2638 Exception::Exception() {
2641 Exception::Exception(String format, ...) {
2643 va_start(arg, format);
2644 Message = assemble(format, arg);
2648 Exception::Exception(String format, va_list arg) {
2649 Message = assemble(format, arg);
2658 std::cout <<
"Serialization::Exception: " << Message << std::endl;
2661 String Exception::assemble(String format, va_list arg) {
2663 vasprintf(&buf, format.c_str(), arg);
operation_t
Current activity of Archive object.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
Object & rootObject()
Root C++ object of this archive.
Archive()
Create an "empty" archive.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage()
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
std::string String
Textual string.
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.
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...