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;
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];
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);
1362 static String _encode(
const UIDChain& chain) {
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() {
1558 String s = MAGIC_START;
1559 m_timeModified = time(NULL);
1560 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1561 m_timeCreated = m_timeModified;
1562 s += _encodeRootBlob();
1563 m_rawData.resize(s.length() + 1);
1564 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1565 m_isModified =
false;
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);
1923 memcpy(&
rawData[0], data, size);
1943 if (m_isModified) encode();
1971 return m_isModified;
1980 m_allObjects.clear();
1984 m_isModified =
false;
1985 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2009 if (m_name ==
name)
return;
2011 m_isModified =
true;
2035 if (m_comment ==
comment)
return;
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");
2063 return m_timeCreated;
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;
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()) {
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;
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()) {
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;
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()) {
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;
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()) {
2335 pObject->m_data.resize(type.
size());
2336 bool* ptr = (
bool*)&pObject->m_data[0];
2338 m_isModified =
true;
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()) {
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;
2379 if (!
object)
return;
2380 const DataType& type =
object.type();
2385 else if (type.
isBool()) {
2386 String val = toLowerCase(value);
2387 if (val ==
"true" || val ==
"yes" || val ==
"1")
2389 else if (val ==
"false" || val ==
"no" || val ==
"0")
2398 throw Exception(
"Not a primitive data type");
2413 if (
object.type().isClass())
2414 throw Exception(
"Object is class type");
2415 const Object* pObject = &object;
2416 if (
object.type().isPointer()) {
2418 if (!obj)
return "";
2421 return _primitiveObjectValueToString(*pObject);
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()) {
2444 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2459 if (!
object.type().isReal())
2460 throw Exception(
"Object is not an real type");
2461 const Object* pObject = &object;
2462 if (
object.type().isPointer()) {
2467 return _primitiveObjectValueToNumber<double>(*pObject);
2481 if (!
object.type().isBool())
2482 throw Exception(
"Object is not a bool");
2483 const Object* pObject = &object;
2484 if (
object.type().isPointer()) {
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());
2520 String* pDst = (String*)(
void*)dstObj.uid().id;
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);
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage()
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
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...