libgig 4.5.2
Serialization.cpp
1/***************************************************************************
2 * *
3 * Copyright (C) 2017-2025 Christian Schoenebeck *
4 * <cuse@users.sourceforge.net> *
5 * *
6 * This library is part of libgig. *
7 * *
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24// enable implementation specific declarations in Serialization.h required to
25// build this C++ unit, which should be ignored in the public API though
26#define LIBGIG_SERIALIZATION_INTERNAL 1
27
28#include "Serialization.h"
29
30#include <iostream>
31#include <string.h> // for memcpy()
32#include <cstdint> // for uintptr_t
33#ifdef _MSC_VER
34# include <windows.h>
35# include <dbghelp.h>
36#else
37# include <cxxabi.h>
38#endif
39#include "helper.h"
40
41#define LIBGIG_EPOCH_TIME ((time_t)0)
42
43namespace Serialization {
44
45 // *************** UID ***************
46 // *
47
48 static UID _createNullUID() {
49 const UID uid = { NULL, 0 };
50 return uid;
51 }
52
53 const UID NO_UID = _createNullUID();
54
66 bool UID::isValid() const {
67 return id != NULL && id != (void*)-1 && size;
68 }
69
70 // *************** DataType ***************
71 // *
72
84 std::map<String,DataType::NativeType> DataType::m_nativeTypes;
85
96 m_size = 0;
97 m_isPointer = false;
98 }
99
128 String customType1, String customType2)
129 {
130 m_size = size;
131 m_isPointer = isPointer;
132 m_baseTypeName = baseType;
133 m_customTypeName = customType1;
134 m_customTypeName2 = customType2;
135 }
136
147 bool DataType::isValid() const {
148 return m_size;
149 }
150
156 bool DataType::isPointer() const {
157 return m_isPointer;
158 }
159
185 bool DataType::isClass() const {
186 return m_baseTypeName == "class";
187 }
188
210 return !isClass() && !isArray() && !isSet() && !isMap();
211 }
212
223 bool DataType::isString() const {
224 return m_baseTypeName == "String";
225 }
226
241 bool DataType::isInteger() const {
242 return m_baseTypeName.substr(0, 3) == "int" ||
243 m_baseTypeName.substr(0, 4) == "uint";
244 }
245
258 bool DataType::isReal() const {
259 return m_baseTypeName.substr(0, 4) == "real";
260 }
261
273 bool DataType::isBool() const {
274 return m_baseTypeName == "bool";
275 }
276
288 bool DataType::isEnum() const {
289 return m_baseTypeName == "enum";
290 }
291
304 bool DataType::isArray() const {
305 return m_baseTypeName == "Array";
306 }
307
320 bool DataType::isSet() const {
321 return m_baseTypeName == "Set";
322 }
323
336 bool DataType::isMap() const {
337 return m_baseTypeName == "Map";
338 }
339
353 bool DataType::isSigned() const {
354 return m_baseTypeName.substr(0, 3) == "int" ||
355 isReal();
356 }
357
376 bool DataType::operator==(const DataType& other) const {
377 return m_baseTypeName == other.m_baseTypeName &&
378 m_customTypeName == other.m_customTypeName &&
379 m_customTypeName2 == other.m_customTypeName2 &&
380 (m_size == other.m_size || (isClass() && other.isClass())) &&
381 m_isPointer == other.m_isPointer;
382 }
383
397 return m_baseTypeName + "," +
398 m_customTypeName + "," +
399 m_customTypeName2 + "," +
400 ToString(isClass()) + "," +
401 ToString(m_isPointer);
402 }
403
409 bool DataType::operator!=(const DataType& other) const {
410 return !operator==(other);
411 }
412
424 bool DataType::operator<(const DataType& other) const {
425 return m_baseTypeName < other.m_baseTypeName ||
426 (m_baseTypeName == other.m_baseTypeName &&
427 (m_customTypeName < other.m_customTypeName ||
428 (m_customTypeName == other.m_customTypeName &&
429 (m_customTypeName2 < other.m_customTypeName2 ||
430 (m_customTypeName2 == other.m_customTypeName2 &&
431 (m_size < other.m_size ||
432 (m_size == other.m_size &&
433 m_isPointer < other.m_isPointer)))))));
434 }
435
447 bool DataType::operator>(const DataType& other) const {
448 return !(operator==(other) || operator<(other));
449 }
450
466 String s = m_baseTypeName;
467 if (!m_customTypeName.empty())
468 s += " " + customTypeName(true);
469 if (!m_customTypeName2.empty())
470 s += " " + customTypeName2(true);
471 if (isPointer())
472 s += " pointer";
473 return s;
474 }
475
506 return m_baseTypeName;
507 }
508
509 static String _demangleTypeName(const char* name) {
510#ifdef _MSC_VER
511 const size_t MAXLENGTH = 1024;
512 char result[MAXLENGTH];
513
514 //FIXME: calling UnDecorateSymbolName() is not thread safe!
515 //Skip the first char
516 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
517 if (size)
518 {
519 return result;
520 }
521 return name;
522#else
523 int status;
524 char* result =
525 abi::__cxa_demangle(name, 0, 0, &status);
526 String sResult = result;
527 free(result);
528 return (status == 0) ? sResult : name;
529#endif
530 }
531
568 String DataType::customTypeName(bool demangle) const {
569 if (!demangle) return m_customTypeName;
570 return _demangleTypeName(m_customTypeName.c_str());
571 }
572
580 String DataType::customTypeName2(bool demangle) const {
581 if (!demangle) return m_customTypeName2;
582 return _demangleTypeName(m_customTypeName2.c_str());
583 }
584
598 Object DataType::newInstance(Archive* archive) const {
599 const String id = internalID();
600 auto itNativeType = m_nativeTypes.find(id);
601 if (itNativeType == m_nativeTypes.end()) {
602 fprintf(stderr,
603 "(De)serialization Failure: cannot create new instance of "
604 "unknown data type '%s' !\n",
605 asLongDescr().c_str());
606 assert(false && "You may need to explicitly register this data "
607 "type by either calling "
608 "DataType::registerNativeType<T>() or using class "
609 "NativeDataTypeRegistry");
610 }
611 const std::function<Object(Archive*)>& allocFn = itNativeType->second.allocFn;
612 return allocFn(archive);
613 }
614
615 // *************** Member ***************
616 // *
617
631 m_uid = NO_UID;
632 m_offset = 0;
633 m_parentUID = NO_UID;
634 }
635
636 Member::Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent) {
637 m_name = name;
638 m_uid = uid;
639 m_offset = offset;
640 m_type = type;
641 m_parentUID = parent.uid();
642 }
643
658 UID Member::uid() const {
659 return m_uid;
660 }
661
670 return m_parentUID;
671 }
672
694 return m_name;
695 }
696
738 ssize_t Member::offset() const {
739 return m_offset;
740 }
741
746 const DataType& Member::type() const {
747 return m_type;
748 }
749
760 bool Member::isValid() const {
761 return m_uid && !m_name.empty() && m_type;
762 }
763
772 bool Member::operator==(const Member& other) const {
773 return m_uid == other.m_uid &&
774 m_offset == other.m_offset &&
775 m_name == other.m_name &&
776 m_type == other.m_type;
777 }
778
784 bool Member::operator!=(const Member& other) const {
785 return !operator==(other);
786 }
787
800 bool Member::operator<(const Member& other) const {
801 return m_uid < other.m_uid ||
802 (m_uid == other.m_uid &&
803 (m_offset < other.m_offset ||
804 (m_offset == other.m_offset &&
805 (m_name < other.m_name ||
806 (m_name == other.m_name &&
807 m_type < other.m_type)))));
808 }
809
822 bool Member::operator>(const Member& other) const {
823 return !(operator==(other) || operator<(other));
824 }
825
826 // *************** Object ***************
827 // *
828
841 m_parentUID = NO_UID;
842 m_version = 0;
843 m_minVersion = 0;
844 }
845
864 m_type = type;
865 m_uid = uidChain;
866 m_parentUID = parent.uid();
867 m_version = 0;
868 m_minVersion = 0;
869 //m_data.resize(type.size());
870 }
871
882 bool Object::isValid() const {
883 return m_type && !m_uid.empty();
884 }
885
897 UID Object::uid(int index) const {
898 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
899 }
900
914 return m_parentUID;
915 }
916
917 static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
918 if (type.isPointer()) {
919 // assuming hex encoding
920 uintptr_t addr = std::stoull(s, NULL, 16);
921 *(void**)ptr = reinterpret_cast<void*>(addr);
922 } else if (type.isPrimitive()) {
923 if (type.isInteger() || type.isEnum()) {
924 if (type.isSigned()) {
925 if (type.size() == 1)
926 *(int8_t*)ptr = strTo<int8_t>(s);
927 else if (type.size() == 2)
928 *(int16_t*)ptr = strTo<int16_t>(s);
929 else if (type.size() == 4)
930 *(int32_t*)ptr = strTo<int32_t>(s);
931 else if (type.size() == 8)
932 *(int64_t*)ptr = strTo<int64_t>(s);
933 else
934 assert(false /* unknown signed int type size */);
935 } else {
936 if (type.size() == 1)
937 *(uint8_t*)ptr = strTo<uint8_t>(s);
938 else if (type.size() == 2)
939 *(uint16_t*)ptr = strTo<uint16_t>(s);
940 else if (type.size() == 4)
941 *(uint32_t*)ptr = strTo<uint32_t>(s);
942 else if (type.size() == 8)
943 *(uint64_t*)ptr = strTo<uint64_t>(s);
944 else
945 assert(false /* unknown unsigned int type size */);
946 }
947 } else if (type.isReal()) {
948 if (type.size() == sizeof(float))
949 *(float*)ptr = strTo<float>(s);
950 else if (type.size() == sizeof(double))
951 *(double*)ptr = strTo<double>(s);
952 else
953 assert(false /* unknown floating point type */);
954 } else if (type.isBool()) {
955 String lower = toLowerCase(s);
956 const bool b = lower != "0" && lower != "false" && lower != "no";
957 *(bool*)ptr = b;
958 } else if (type.isString()) {
959 *(String*)ptr = s;
960 } else {
961 assert(false /* no built-in cast from string support for this data type */);
962 }
963 }
964 }
965
982 const ID& id = uid().id;
983 void* ptr = (void*)id;
984 _setNativeValueFromString(ptr, m_type, s.c_str());
985 }
986
993 const UIDChain& Object::uidChain() const {
994 return m_uid;
995 }
996
1002 const DataType& Object::type() const {
1003 return m_type;
1004 }
1005
1028 const RawData& Object::rawData() const {
1029 return m_data;
1030 }
1031
1043 return m_version;
1044 }
1045
1058 return m_minVersion;
1059 }
1060
1093 std::vector<Member>& Object::members() {
1094 return m_members;
1095 }
1096
1103 const std::vector<Member>& Object::members() const {
1104 return m_members;
1105 }
1106
1117 bool Object::operator==(const Object& other) const {
1118 // ignoring all other member variables here
1119 // (since UID stands for "unique" ;-) )
1120 return m_uid == other.m_uid &&
1121 m_type == other.m_type;
1122 }
1123
1129 bool Object::operator!=(const Object& other) const {
1130 return !operator==(other);
1131 }
1132
1145 bool Object::operator<(const Object& other) const {
1146 // ignoring all other member variables here
1147 // (since UID stands for "unique" ;-) )
1148 return m_uid < other.m_uid ||
1149 (m_uid == other.m_uid &&
1150 m_type < other.m_type);
1151 }
1152
1165 bool Object::operator>(const Object& other) const {
1166 return !(operator==(other) || operator<(other));
1167 }
1168
1187 bool Object::isVersionCompatibleTo(const Object& other) const {
1188 if (this->version() == other.version())
1189 return true;
1190 if (this->version() > other.version())
1191 return this->minVersion() <= other.version();
1192 else
1193 return other.minVersion() <= this->version();
1194 }
1195
1196 void Object::setVersion(Version v) {
1197 m_version = v;
1198 }
1199
1200 void Object::setMinVersion(Version v) {
1201 m_minVersion = v;
1202 }
1203
1234 for (int i = 0; i < m_members.size(); ++i)
1235 if (m_members[i].name() == name)
1236 return m_members[i];
1237 return Member();
1238 }
1239
1255 if (!uid) return Member();
1256 for (int i = 0; i < m_members.size(); ++i)
1257 if (m_members[i].uid() == uid)
1258 return m_members[i];
1259 return Member();
1260 }
1261
1262 void Object::remove(const Member& member) {
1263 for (int i = 0; i < m_members.size(); ++i) {
1264 if (m_members[i] == member) {
1265 m_members.erase(m_members.begin() + i);
1266 return;
1267 }
1268 }
1269 }
1270
1286 std::vector<Member> Object::membersOfType(const DataType& type) const {
1287 std::vector<Member> v;
1288 for (int i = 0; i < m_members.size(); ++i) {
1289 const Member& member = m_members[i];
1290 if (member.type() == type)
1291 v.push_back(member);
1292 }
1293 return v;
1294 }
1295
1327 int Object::sequenceIndexOf(const Member& member) const {
1328 for (int i = 0; i < m_members.size(); ++i)
1329 if (m_members[i] == member)
1330 return i;
1331 return -1;
1332 }
1333
1334 // *************** Archive ***************
1335 // *
1336
1356 m_operation = OPERATION_NONE;
1357 m_root = NO_UID;
1358 m_isModified = false;
1359 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1360 }
1361
1378 m_operation = OPERATION_NONE;
1379 m_root = NO_UID;
1380 m_isModified = false;
1381 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1382 decode(data);
1383 }
1384
1405 Archive::Archive(const uint8_t* data, size_t size) {
1406 m_operation = OPERATION_NONE;
1407 m_root = NO_UID;
1408 m_isModified = false;
1409 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1410 decode(data, size);
1411 }
1412
1413 Archive::~Archive() {
1414 }
1415
1427 return m_allObjects[m_root];
1428 }
1429
1430 static String _encodeBlob(String data) {
1431 return ToString(data.length()) + ":" + data;
1432 }
1433
1434 static String _encode(const UID& uid) {
1435 String s;
1436 s += _encodeBlob(ToString(size_t(uid.id)));
1437 s += _encodeBlob(ToString(size_t(uid.size)));
1438 return _encodeBlob(s);
1439 }
1440
1441 static String _encode(const time_t& time) {
1442 return _encodeBlob(ToString(time));
1443 }
1444
1445 static String _encode(const DataType& type) {
1446 String s;
1447
1448 // Srx v1.0 format (mandatory):
1449 s += _encodeBlob(type.baseTypeName());
1450 s += _encodeBlob(type.customTypeName());
1451 s += _encodeBlob(ToString(type.size()));
1452 s += _encodeBlob(ToString(type.isPointer()));
1453
1454 // Srx v1.1 format:
1455 s += _encodeBlob(type.customTypeName2());
1456
1457 return _encodeBlob(s);
1458 }
1459
1460 static String _encode(const UIDChain& chain) {
1461 String s;
1462 for (int i = 0; i < chain.size(); ++i)
1463 s += _encode(chain[i]);
1464 return _encodeBlob(s);
1465 }
1466
1467 static String _encode(const Member& member) {
1468 String s;
1469 s += _encode(member.uid());
1470 s += _encodeBlob(ToString(member.offset()));
1471 s += _encodeBlob(member.name());
1472 s += _encode(member.type());
1473 return _encodeBlob(s);
1474 }
1475
1476 static String _encode(const std::vector<Member>& members) {
1477 String s;
1478 for (int i = 0; i < members.size(); ++i)
1479 s += _encode(members[i]);
1480 return _encodeBlob(s);
1481 }
1482
1483 static String _primitiveObjectValueToString(const Object& obj) {
1484 String s;
1485 const DataType& type = obj.type();
1486 const ID& id = obj.uid().id;
1487 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1488 if (!obj.m_data.empty())
1489 assert(type.size() == obj.m_data.size());
1490 if (type.isPrimitive() && !type.isPointer()) {
1491 if (type.isInteger() || type.isEnum()) {
1492 if (type.isSigned()) {
1493 if (type.size() == 1)
1494 s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
1495 else if (type.size() == 2)
1496 s = ToString(*(int16_t*)ptr);
1497 else if (type.size() == 4)
1498 s = ToString(*(int32_t*)ptr);
1499 else if (type.size() == 8)
1500 s = ToString(*(int64_t*)ptr);
1501 else
1502 assert(false /* unknown signed int type size */);
1503 } else {
1504 if (type.size() == 1)
1505 s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
1506 else if (type.size() == 2)
1507 s = ToString(*(uint16_t*)ptr);
1508 else if (type.size() == 4)
1509 s = ToString(*(uint32_t*)ptr);
1510 else if (type.size() == 8)
1511 s = ToString(*(uint64_t*)ptr);
1512 else
1513 assert(false /* unknown unsigned int type size */);
1514 }
1515 } else if (type.isReal()) {
1516 if (type.size() == sizeof(float))
1517 s = ToString(*(float*)ptr);
1518 else if (type.size() == sizeof(double))
1519 s = ToString(*(double*)ptr);
1520 else
1521 assert(false /* unknown floating point type */);
1522 } else if (type.isBool()) {
1523 s = ToString(*(bool*)ptr);
1524 } else if (type.isString()) {
1525 s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1526 } else {
1527 assert(false /* unknown primitive type */);
1528 }
1529 }
1530 return s;
1531 }
1532
1533 template<typename T>
1534 inline T _stringToNumber(const String& s) {
1535 assert(false /* String cast to unknown primitive number type */);
1536 }
1537
1538 template<>
1539 inline int64_t _stringToNumber(const String& s) {
1540 return strTo<int64_t>(s);
1541 }
1542
1543 template<>
1544 inline double _stringToNumber(const String& s) {
1545 return strTo<double>(s);
1546 }
1547
1548 template<>
1549 inline bool _stringToNumber(const String& s) {
1550 return strTo<bool>(s);
1551 }
1552
1553 template<typename T>
1554 static T _primitiveObjectValueToNumber(const Object& obj) {
1555 T value = 0;
1556 const DataType& type = obj.type();
1557 const ID& id = obj.uid().id;
1558 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1559 if (!obj.m_data.empty())
1560 assert(type.size() == obj.m_data.size());
1561 if (type.isPrimitive() && !type.isPointer()) {
1562 if (type.isInteger() || type.isEnum()) {
1563 if (type.isSigned()) {
1564 if (type.size() == 1)
1565 value = (T)*(int8_t*)ptr;
1566 else if (type.size() == 2)
1567 value = (T)*(int16_t*)ptr;
1568 else if (type.size() == 4)
1569 value = (T)*(int32_t*)ptr;
1570 else if (type.size() == 8)
1571 value = (T)*(int64_t*)ptr;
1572 else
1573 assert(false /* unknown signed int type size */);
1574 } else {
1575 if (type.size() == 1)
1576 value = (T)*(uint8_t*)ptr;
1577 else if (type.size() == 2)
1578 value = (T)*(uint16_t*)ptr;
1579 else if (type.size() == 4)
1580 value = (T)*(uint32_t*)ptr;
1581 else if (type.size() == 8)
1582 value = (T)*(uint64_t*)ptr;
1583 else
1584 assert(false /* unknown unsigned int type size */);
1585 }
1586 } else if (type.isReal()) {
1587 if (type.size() == sizeof(float))
1588 value = (T)*(float*)ptr;
1589 else if (type.size() == sizeof(double))
1590 value = (T)*(double*)ptr;
1591 else
1592 assert(false /* unknown floating point type */);
1593 } else if (type.isBool()) {
1594 value = (T)*(bool*)ptr;
1595 } else if (type.isString()) {
1596 value = _stringToNumber<T>(
1597 obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1598 );
1599 } else {
1600 assert(false /* unknown primitive type */);
1601 }
1602 }
1603 return value;
1604 }
1605
1606 static String _encodePrimitiveValue(const Object& obj) {
1607 return _encodeBlob( _primitiveObjectValueToString(obj) );
1608 }
1609
1610 static String _encode(const Object& obj) {
1611 String s;
1612 s += _encode(obj.type());
1613 s += _encodeBlob(ToString(obj.version()));
1614 s += _encodeBlob(ToString(obj.minVersion()));
1615 s += _encode(obj.uidChain());
1616 s += _encode(obj.members());
1617 s += _encodePrimitiveValue(obj);
1618 // Srx v1.2 format:
1619 s += _encode(obj.parentUID());
1620
1621 return _encodeBlob(s);
1622 }
1623
1624 String _encode(const Archive::ObjectPool& objects) {
1625 String s;
1626 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1627 itObject != objects.end(); ++itObject)
1628 {
1629 const Object& obj = itObject->second;
1630 s += _encode(obj);
1631 }
1632 return _encodeBlob(s);
1633 }
1634
1635 /*
1636 * Srx format history:
1637 * - 1.0: Initial version.
1638 * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1639 * 2nd custom type name (e.g. "Map" types which always contain two
1640 * user defined types).
1641 * - 1.2: Stores objects' parent UID, which projects which native data
1642 * structure was contained within the boundaries of which specific
1643 * other data structure. This permits to automatically restore native
1644 * pointers, as structured layout info is required to identify
1645 * whether a pointer was just a "weak" pointer or a "strong" pointer.
1646 * For a "strong" pointer the pointed data has to be allocated
1647 * automatically by this framework, whereas for "weak" pointers not.
1648 */
1649 #define MAGIC_START "Srx1v"
1650 #define ENCODING_FORMAT_MINOR_VERSION 2
1651
1652 String Archive::_encodeRootBlob() {
1653 String s;
1654 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1655 s += _encode(m_root);
1656 s += _encode(m_allObjects);
1657 s += _encodeBlob(m_name);
1658 s += _encodeBlob(m_comment);
1659 s += _encode(m_timeCreated);
1660 s += _encode(m_timeModified);
1661 return _encodeBlob(s);
1662 }
1663
1664 void Archive::encode() {
1665 m_rawData.clear();
1666 String s = MAGIC_START;
1667 m_timeModified = time(NULL);
1668 if (m_timeCreated == LIBGIG_EPOCH_TIME)
1669 m_timeCreated = m_timeModified;
1670 s += _encodeRootBlob();
1671 m_rawData.resize(s.length() + 1);
1672 memcpy(&m_rawData[0], &s[0], s.length() + 1);
1673 m_isModified = false;
1674 }
1675
1676 struct _Blob {
1677 const char* p;
1678 const char* end;
1679 };
1680
1681 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1682 if (!bThrow && p >= end) {
1683 const _Blob blob = { p, end };
1684 return blob;
1685 }
1686 size_t sz = 0;
1687 for (; true; ++p) {
1688 if (p >= end)
1689 throw Exception("Decode Error: Missing blob");
1690 const char& c = *p;
1691 if (c == ':') break;
1692 if (c < '0' || c > '9')
1693 throw Exception("Decode Error: Missing blob size");
1694 sz *= 10;
1695 sz += size_t(c - '0');
1696 }
1697 ++p;
1698 if (p + sz > end)
1699 throw Exception("Decode Error: Premature end of blob");
1700 const _Blob blob = { p, p + sz };
1701 return blob;
1702 }
1703
1704 template<typename T_int>
1705 static T_int _popIntBlob(const char*& p, const char* end) {
1706 _Blob blob = _decodeBlob(p, end);
1707 p = blob.p;
1708 end = blob.end;
1709
1710 T_int sign = 1;
1711 T_int i = 0;
1712 if (p >= end)
1713 throw Exception("Decode Error: premature end of int blob");
1714 if (*p == '-') {
1715 sign = -1;
1716 ++p;
1717 }
1718 for (; p < end; ++p) {
1719 const char& c = *p;
1720 if (c < '0' || c > '9')
1721 throw Exception("Decode Error: Invalid int blob format");
1722 i *= 10;
1723 i += size_t(c - '0');
1724 }
1725 return i * sign;
1726 }
1727
1728 template<typename T_int>
1729 static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
1730 const T_int i = _popIntBlob<T_int>(p, end);
1731 *(T_int*)&rawData[0] = i;
1732 }
1733
1734 template<typename T_real>
1735 static T_real _popRealBlob(const char*& p, const char* end) {
1736 _Blob blob = _decodeBlob(p, end);
1737 p = blob.p;
1738 end = blob.end;
1739
1740 if (p >= end || (end - p) < 1)
1741 throw Exception("Decode Error: premature end of real blob");
1742
1743 String s(p, size_t(end - p));
1744
1745 T_real r;
1746 if (sizeof(T_real) <= sizeof(double))
1747 r = strTo<T_real>(s);
1748 else
1749 assert(false /* unknown real type */);
1750
1751 p += s.length();
1752
1753 return r;
1754 }
1755
1756 template<typename T_real>
1757 static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
1758 const T_real r = _popRealBlob<T_real>(p, end);
1759 *(T_real*)&rawData[0] = r;
1760 }
1761
1762 static String _popStringBlob(const char*& p, const char* end) {
1763 _Blob blob = _decodeBlob(p, end);
1764 p = blob.p;
1765 end = blob.end;
1766 if (end - p < 0)
1767 throw Exception("Decode Error: missing String blob");
1768 String s;
1769 const size_t sz = end - p;
1770 s.resize(sz);
1771 memcpy(&s[0], p, sz);
1772 p += sz;
1773 return s;
1774 }
1775
1776 static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1777 String s = _popStringBlob(p, end);
1778 rawData.resize(s.length() + 1);
1779 strcpy((char*)&rawData[0], &s[0]);
1780 }
1781
1782 static time_t _popTimeBlob(const char*& p, const char* end) {
1783 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1784 return (time_t) i;
1785 }
1786
1787 static DataType _popDataTypeBlob(const char*& p, const char* end) {
1788 _Blob blob = _decodeBlob(p, end);
1789 p = blob.p;
1790 end = blob.end;
1791
1792 DataType type;
1793
1794 // Srx v1.0 format (mandatory):
1795 type.m_baseTypeName = _popStringBlob(p, end);
1796 type.m_customTypeName = _popStringBlob(p, end);
1797 type.m_size = _popIntBlob<int>(p, end);
1798 type.m_isPointer = _popIntBlob<bool>(p, end);
1799
1800 // Srx v1.1 format (optional):
1801 if (p < end)
1802 type.m_customTypeName2 = _popStringBlob(p, end);
1803
1804 return type;
1805 }
1806
1807 static UID _popUIDBlob(const char*& p, const char* end) {
1808 _Blob blob = _decodeBlob(p, end);
1809 p = blob.p;
1810 end = blob.end;
1811
1812 if (p >= end)
1813 throw Exception("Decode Error: premature end of UID blob");
1814
1815 const ID id = (ID) _popIntBlob<size_t>(p, end);
1816 const size_t size = _popIntBlob<size_t>(p, end);
1817
1818 const UID uid = { id, size };
1819 return uid;
1820 }
1821
1822 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1823 _Blob blob = _decodeBlob(p, end);
1824 p = blob.p;
1825 end = blob.end;
1826
1827 UIDChain chain;
1828 while (p < end) {
1829 const UID uid = _popUIDBlob(p, end);
1830 chain.push_back(uid);
1831 }
1832 assert(!chain.empty());
1833 return chain;
1834 }
1835
1836 static Member _popMemberBlob(const char*& p, const char* end) {
1837 _Blob blob = _decodeBlob(p, end, false);
1838 p = blob.p;
1839 end = blob.end;
1840
1841 Member m;
1842 if (p >= end) return m;
1843
1844 m.m_uid = _popUIDBlob(p, end);
1845 m.m_offset = _popIntBlob<ssize_t>(p, end);
1846 m.m_name = _popStringBlob(p, end);
1847 m.m_type = _popDataTypeBlob(p, end);
1848 assert(m.type());
1849 assert(!m.name().empty());
1850 assert(m.uid().isValid());
1851 return m;
1852 }
1853
1854 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1855 _Blob blob = _decodeBlob(p, end, false);
1856 p = blob.p;
1857 end = blob.end;
1858
1859 std::vector<Member> members;
1860 while (p < end) {
1861 const Member member = _popMemberBlob(p, end);
1862 if (member)
1863 members.push_back(member);
1864 else
1865 break;
1866 }
1867 return members;
1868 }
1869
1870 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
1871 const DataType& type = obj.type();
1872 if (type.isPrimitive() && !type.isPointer()) {
1873 obj.m_data.resize(type.size());
1874 if (type.isInteger() || type.isEnum()) {
1875 if (type.isSigned()) {
1876 if (type.size() == 1)
1877 _popIntBlob<int8_t>(p, end, obj.m_data);
1878 else if (type.size() == 2)
1879 _popIntBlob<int16_t>(p, end, obj.m_data);
1880 else if (type.size() == 4)
1881 _popIntBlob<int32_t>(p, end, obj.m_data);
1882 else if (type.size() == 8)
1883 _popIntBlob<int64_t>(p, end, obj.m_data);
1884 else
1885 assert(false /* unknown signed int type size */);
1886 } else {
1887 if (type.size() == 1)
1888 _popIntBlob<uint8_t>(p, end, obj.m_data);
1889 else if (type.size() == 2)
1890 _popIntBlob<uint16_t>(p, end, obj.m_data);
1891 else if (type.size() == 4)
1892 _popIntBlob<uint32_t>(p, end, obj.m_data);
1893 else if (type.size() == 8)
1894 _popIntBlob<uint64_t>(p, end, obj.m_data);
1895 else
1896 assert(false /* unknown unsigned int type size */);
1897 }
1898 } else if (type.isReal()) {
1899 if (type.size() == sizeof(float))
1900 _popRealBlob<float>(p, end, obj.m_data);
1901 else if (type.size() == sizeof(double))
1902 _popRealBlob<double>(p, end, obj.m_data);
1903 else
1904 assert(false /* unknown floating point type */);
1905 } else if (type.isBool()) {
1906 _popIntBlob<uint8_t>(p, end, obj.m_data);
1907 } else if (type.isString()) {
1908 _popStringBlob(p, end, obj.m_data);
1909 } else {
1910 assert(false /* unknown primitive type */);
1911 }
1912
1913 } else {
1914 // don't whine if the empty blob was not added on encoder side
1915 _Blob blob = _decodeBlob(p, end, false);
1916 p = blob.p;
1917 end = blob.end;
1918 }
1919 }
1920
1921 static Object _popObjectBlob(const char*& p, const char* end) {
1922 _Blob blob = _decodeBlob(p, end, false);
1923 p = blob.p;
1924 end = blob.end;
1925
1926 Object obj;
1927 if (p >= end) return obj;
1928
1929 obj.m_type = _popDataTypeBlob(p, end);
1930 obj.m_version = _popIntBlob<Version>(p, end);
1931 obj.m_minVersion = _popIntBlob<Version>(p, end);
1932 obj.m_uid = _popUIDChainBlob(p, end);
1933 obj.m_members = _popMembersBlob(p, end);
1934 _popPrimitiveValue(p, end, obj);
1935 assert(obj.type());
1936
1937 // Srx v1.2 format (optional):
1938 if (p < end)
1939 obj.m_parentUID = _popUIDBlob(p, end);
1940
1941 return obj;
1942 }
1943
1944 void Archive::_popObjectsBlob(const char*& p, const char* end) {
1945 _Blob blob = _decodeBlob(p, end, false);
1946 p = blob.p;
1947 end = blob.end;
1948
1949 if (p >= end)
1950 throw Exception("Decode Error: Premature end of objects blob");
1951
1952 while (true) {
1953 const Object obj = _popObjectBlob(p, end);
1954 if (!obj) break;
1955 m_allObjects[obj.uid()] = obj;
1956 }
1957 }
1958
1959 void Archive::_popRootBlob(const char*& p, const char* end) {
1960 _Blob blob = _decodeBlob(p, end, false);
1961 p = blob.p;
1962 end = blob.end;
1963
1964 if (p >= end)
1965 throw Exception("Decode Error: Premature end of root blob");
1966
1967 // just in case this encoding format will be extended in future
1968 // (currently not used)
1969 const int formatMinorVersion = _popIntBlob<int>(p, end);
1970
1971 m_root = _popUIDBlob(p, end);
1972 if (!m_root)
1973 throw Exception("Decode Error: No root object");
1974
1975 _popObjectsBlob(p, end);
1976 if (!m_allObjects[m_root])
1977 throw Exception("Decode Error: Missing declared root object");
1978
1979 m_name = _popStringBlob(p, end);
1980 m_comment = _popStringBlob(p, end);
1981 m_timeCreated = _popTimeBlob(p, end);
1982 m_timeModified = _popTimeBlob(p, end);
1983 }
1984
2000 void Archive::decode(const RawData& data) {
2001 m_rawData = data;
2002 m_allObjects.clear();
2003 m_isModified = false;
2004 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2005 const char* p = (const char*) &data[0];
2006 const char* end = p + data.size();
2007 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
2008 throw Exception("Decode Error: Magic start missing!");
2009 p += strlen(MAGIC_START);
2010 _popRootBlob(p, end);
2011 }
2012
2033 void Archive::decode(const uint8_t* data, size_t size) {
2035 rawData.resize(size);
2036 memcpy(&rawData[0], data, size);
2037 decode(rawData);
2038 }
2039
2056 if (m_isModified) encode();
2057 return m_rawData;
2058 }
2059
2066 return MAGIC_START;
2067 }
2068
2083 bool Archive::isModified() const {
2084 return m_isModified;
2085 }
2086
2093 m_allObjects.clear();
2094 m_operation = OPERATION_NONE;
2095 m_root = NO_UID;
2096 m_rawData.clear();
2097 m_isModified = false;
2098 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
2099 }
2100
2109 return m_name;
2110 }
2111
2122 if (m_name == name) return;
2123 m_name = name;
2124 m_isModified = true;
2125 }
2126
2135 return m_comment;
2136 }
2137
2148 if (m_comment == comment) return;
2149 m_comment = comment;
2150 m_isModified = true;
2151 }
2152
2153 static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2154 tm* pTm;
2155 switch (base) {
2156 case LOCAL_TIME:
2157 pTm = localtime(&time);
2158 break;
2159 case UTC_TIME:
2160 pTm = gmtime(&time);
2161 break;
2162 default:
2163 throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2164 }
2165 if (!pTm)
2166 throw Exception("Failed assembling time stamp structure");
2167 return *pTm;
2168 }
2169
2176 return m_timeCreated;
2177 }
2178
2185 return m_timeModified;
2186 }
2187
2199 return _convertTimeStamp(m_timeCreated, base);
2200 }
2201
2213 return _convertTimeStamp(m_timeModified, base);
2214 }
2215
2233 void Archive::removeMember(Object& parent, const Member& member) {
2234 parent.remove(member);
2235 m_isModified = true;
2236 }
2237
2253 void Archive::remove(const Object& obj) {
2254 //FIXME: Should traverse from root object and remove all members associated with this object
2255 if (!obj.uid()) return;
2256 m_allObjects.erase(obj.uid());
2257 m_isModified = true;
2258 }
2259
2273 return m_allObjects[uid];
2274 }
2275
2291 ObjectPool::iterator it = m_allObjects.find(uid);
2292 if (it != m_allObjects.end())
2293 return it->second;
2294
2295 // find all objects with the same ID (i.e. memory address) AND being
2296 // larger than expected by passed base UID
2297 std::map<size_t,UID> matches;
2298 for (const auto& it : m_allObjects)
2299 if (it.first.id == uid.id && it.first.size > uid.size)
2300 matches[it.first.size] = it.first;
2301
2302 if (matches.empty())
2303 return ObjectPool::invalidObject();
2304
2305 // return the next larger object found
2306 return m_allObjects[matches.begin()->second];
2307 }
2308
2318 return m_allObjects[obj.parentUID()];
2319 }
2320
2327 return m_allObjects[member.parentUID()];
2328 }
2329
2341 if (!object) return;
2342 object.setVersion(v);
2343 m_isModified = true;
2344 }
2345
2357 if (!object) return;
2358 object.setMinVersion(v);
2359 m_isModified = true;
2360 }
2361
2370 void Archive::setEnumValue(Object& object, uint64_t value) {
2371 if (!object) return;
2372 if (!object.type().isEnum())
2373 throw Exception("Not an enum data type");
2374 Object* pObject = &object;
2375 if (object.type().isPointer()) {
2376 Object& obj = objectByUID(object.uid(1));
2377 if (!obj) return;
2378 pObject = &obj;
2379 }
2380 const int nativeEnumSize = sizeof(enum operation_t);
2381 DataType& type = const_cast<DataType&>( pObject->type() );
2382 // original serializer ("sender") might have had a different word size
2383 // than this machine, adjust type object in this case
2384 if (type.size() != nativeEnumSize) {
2385 type.m_size = nativeEnumSize;
2386 }
2387 pObject->m_data.resize(type.size());
2388 void* ptr = &pObject->m_data[0];
2389 if (type.size() == 1)
2390 *(uint8_t*)ptr = (uint8_t)value;
2391 else if (type.size() == 2)
2392 *(uint16_t*)ptr = (uint16_t)value;
2393 else if (type.size() == 4)
2394 *(uint32_t*)ptr = (uint32_t)value;
2395 else if (type.size() == 8)
2396 *(uint64_t*)ptr = (uint64_t)value;
2397 else
2398 assert(false /* unknown enum type size */);
2399 m_isModified = true;
2400 }
2401
2412 void Archive::setIntValue(Object& object, int64_t value) {
2413 if (!object) return;
2414 if (!object.type().isInteger())
2415 throw Exception("Not an integer data type");
2416 Object* pObject = &object;
2417 if (object.type().isPointer()) {
2418 Object& obj = objectByUID(object.uid(1));
2419 if (!obj) return;
2420 pObject = &obj;
2421 }
2422 const DataType& type = pObject->type();
2423 pObject->m_data.resize(type.size());
2424 void* ptr = &pObject->m_data[0];
2425 if (type.isSigned()) {
2426 if (type.size() == 1)
2427 *(int8_t*)ptr = (int8_t)value;
2428 else if (type.size() == 2)
2429 *(int16_t*)ptr = (int16_t)value;
2430 else if (type.size() == 4)
2431 *(int32_t*)ptr = (int32_t)value;
2432 else if (type.size() == 8)
2433 *(int64_t*)ptr = (int64_t)value;
2434 else
2435 assert(false /* unknown signed int type size */);
2436 } else {
2437 if (type.size() == 1)
2438 *(uint8_t*)ptr = (uint8_t)value;
2439 else if (type.size() == 2)
2440 *(uint16_t*)ptr = (uint16_t)value;
2441 else if (type.size() == 4)
2442 *(uint32_t*)ptr = (uint32_t)value;
2443 else if (type.size() == 8)
2444 *(uint64_t*)ptr = (uint64_t)value;
2445 else
2446 assert(false /* unknown unsigned int type size */);
2447 }
2448 m_isModified = true;
2449 }
2450
2462 void Archive::setRealValue(Object& object, double value) {
2463 if (!object) return;
2464 if (!object.type().isReal())
2465 throw Exception("Not a real data type");
2466 Object* pObject = &object;
2467 if (object.type().isPointer()) {
2468 Object& obj = objectByUID(object.uid(1));
2469 if (!obj) return;
2470 pObject = &obj;
2471 }
2472 const DataType& type = pObject->type();
2473 pObject->m_data.resize(type.size());
2474 void* ptr = &pObject->m_data[0];
2475 if (type.size() == sizeof(float))
2476 *(float*)ptr = (float)value;
2477 else if (type.size() == sizeof(double))
2478 *(double*)ptr = (double)value;
2479 else
2480 assert(false /* unknown real type size */);
2481 m_isModified = true;
2482 }
2483
2492 void Archive::setBoolValue(Object& object, bool value) {
2493 if (!object) return;
2494 if (!object.type().isBool())
2495 throw Exception("Not a bool data type");
2496 Object* pObject = &object;
2497 if (object.type().isPointer()) {
2498 Object& obj = objectByUID(object.uid(1));
2499 if (!obj) return;
2500 pObject = &obj;
2501 }
2502 const DataType& type = pObject->type();
2503 pObject->m_data.resize(type.size());
2504 bool* ptr = (bool*)&pObject->m_data[0];
2505 *ptr = value;
2506 m_isModified = true;
2507 }
2508
2518 if (!object) return;
2519 if (!object.type().isString())
2520 throw Exception("Not a String data type");
2521 Object* pObject = &object;
2522 if (object.type().isPointer()) {
2523 Object& obj = objectByUID(object.uid(1));
2524 if (!obj) return;
2525 pObject = &obj;
2526 }
2527 pObject->m_data.resize(value.length() + 1);
2528 char* ptr = (char*) &pObject->m_data[0];
2529 strcpy(ptr, &value[0]);
2530 m_isModified = true;
2531 }
2532
2546 void Archive::setAutoValue(Object& object, String value) {
2547 if (!object) return;
2548 const DataType& type = object.type();
2549 if (type.isInteger())
2550 setIntValue(object, strTo<int64_t>(value));
2551 else if (type.isReal())
2552 setRealValue(object, strTo<double>(value));
2553 else if (type.isBool()) {
2554 String val = toLowerCase(value);
2555 if (val == "true" || val == "yes" || val == "1")
2556 setBoolValue(object, true);
2557 else if (val == "false" || val == "no" || val == "0")
2558 setBoolValue(object, false);
2559 else
2560 setBoolValue(object, strTo<bool>(value));
2561 } else if (type.isString())
2562 setStringValue(object, value);
2563 else if (type.isEnum())
2564 setEnumValue(object, strTo<uint64_t>(value));
2565 else
2566 throw Exception("Not a primitive data type");
2567 }
2568
2579 if (!object)
2580 throw Exception("Invalid object");
2581 if (object.type().isClass())
2582 throw Exception("Object is class type");
2583 const Object* pObject = &object;
2584 if (object.type().isPointer()) {
2585 const Object& obj = objectByUID(object.uid(1));
2586 if (!obj) return "";
2587 pObject = &obj;
2588 }
2589 return _primitiveObjectValueToString(*pObject);
2590 }
2591
2601 int64_t Archive::valueAsInt(const Object& object) {
2602 if (!object)
2603 throw Exception("Invalid object");
2604 if (!object.type().isInteger() && !object.type().isEnum())
2605 throw Exception("Object is neither an integer nor an enum");
2606 const Object* pObject = &object;
2607 if (object.type().isPointer()) {
2608 const Object& obj = objectByUID(object.uid(1));
2609 if (!obj) return 0;
2610 pObject = &obj;
2611 }
2612 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2613 }
2614
2624 double Archive::valueAsReal(const Object& object) {
2625 if (!object)
2626 throw Exception("Invalid object");
2627 if (!object.type().isReal())
2628 throw Exception("Object is not an real type");
2629 const Object* pObject = &object;
2630 if (object.type().isPointer()) {
2631 const Object& obj = objectByUID(object.uid(1));
2632 if (!obj) return 0;
2633 pObject = &obj;
2634 }
2635 return _primitiveObjectValueToNumber<double>(*pObject);
2636 }
2637
2646 bool Archive::valueAsBool(const Object& object) {
2647 if (!object)
2648 throw Exception("Invalid object");
2649 if (!object.type().isBool())
2650 throw Exception("Object is not a bool");
2651 const Object* pObject = &object;
2652 if (object.type().isPointer()) {
2653 const Object& obj = objectByUID(object.uid(1));
2654 if (!obj) return 0;
2655 pObject = &obj;
2656 }
2657 return _primitiveObjectValueToNumber<bool>(*pObject);
2658 }
2659
2660 Archive::operation_t Archive::operation() const {
2661 return m_operation;
2662 }
2663
2664 // *************** Archive::Syncer ***************
2665 // *
2666
2667 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2668 : m_dst(dst), m_src(src)
2669 {
2670 const Object srcRootObj = src.rootObject();
2671 const Object dstRootObj = dst.rootObject();
2672 if (!srcRootObj)
2673 throw Exception("No source root object!");
2674 if (!dstRootObj)
2675 throw Exception("Expected destination root object not found!");
2676 syncObject(dstRootObj, srcRootObj);
2677 }
2678
2679 void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
2680 assert(srcObj.rawData().size() == dstObj.type().size());
2681 void* pDst = (void*)dstObj.uid().id;
2682 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2683 }
2684
2685 void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2686 assert(dstObj.type().isString());
2687 assert(dstObj.type() == srcObj.type());
2688 String* pDst = (String*)(void*)dstObj.uid().id;
2689 *pDst = (String) (const char*) &srcObj.rawData()[0];
2690 }
2691
2692 void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2693 assert(dstObj.type().isArray());
2694 assert(dstObj.type() == srcObj.type());
2695 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2696 }
2697
2698 void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2699 assert(dstObj.type().isSet());
2700 assert(dstObj.type() == srcObj.type());
2701 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2702 }
2703
2704 void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2705 assert(dstObj.type().isMap());
2706 assert(dstObj.type() == srcObj.type());
2707 dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2708 }
2709
2710 void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2711 assert(dstObj.type().isPointer());
2712 assert(dstObj.type() == srcObj.type());
2713 void** ppDst = (void**)dstObj.uid().id;
2714 if (!srcObj.uid(1)) { // NULL pointer on source side ...
2715 *ppDst = NULL;
2716 return;
2717 }
2718 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
2719 assert(pointedSrcObject);
2720 std::map<UID,UID>::iterator uidRelation = m_counterparts.find(srcObj.uid(1));
2721 if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
2722 assert(uidRelation != m_counterparts.end());
2723 const Object& pointedDstObject = m_dst.m_allObjects[uidRelation->second];
2724 assert(pointedDstObject);
2725 *ppDst = (void*)pointedDstObject.uid().id;
2726 } else { // "strong" pointer to object, allocation required ...
2727 assert(pointedSrcObject.type());
2728 Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
2729 assert(pointedDstObject);
2730
2731 m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
2732 *ppDst = (void*)pointedDstObject.uid().id;
2733 syncObject(pointedDstObject, pointedSrcObject);
2734 }
2735 }
2736
2737 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2738 assert(dstObj && srcObj);
2739
2740 // remember UID mapping between source and destination side
2741 //
2742 // As UIDs differ between source archive side and destination archive
2743 // side (as UIDs always translate to native data's real memory address),
2744 // remember their relationship, such that we can later on translate
2745 // objects from source archive side correctly to objects on destination
2746 // side, which is required to sync native pointers correctly for
2747 // pointing to respective correct, real memory address.
2748 const bool alreadySynced =
2749 !m_counterparts.insert({srcObj.uid(), dstObj.uid()}).second;
2750
2751 // Prevent syncing this object again, and thus also prevent endless
2752 // loop on data structures with cyclic relations.
2753 if (alreadySynced)
2754 return; // end of recursion
2755
2756 if (!dstObj.isVersionCompatibleTo(srcObj))
2757 throw Exception("Version incompatible (destination version " +
2758 ToString(dstObj.version()) + " [min. version " +
2759 ToString(dstObj.minVersion()) + "], source version " +
2760 ToString(srcObj.version()) + " [min. version " +
2761 ToString(srcObj.minVersion()) + "])");
2762 if (dstObj.type() != srcObj.type())
2763 throw Exception("Incompatible data structure type (destination type " +
2764 dstObj.type().asLongDescr() + " vs. source type " +
2765 srcObj.type().asLongDescr() + ")");
2766
2767 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2768 if (dstObj.type().isString())
2769 syncString(dstObj, srcObj);
2770 else
2771 syncPrimitive(dstObj, srcObj);
2772 return; // end of recursion
2773 }
2774
2775 if (dstObj.type().isArray()) {
2776 syncArray(dstObj, srcObj);
2777 return;
2778 }
2779
2780 if (dstObj.type().isSet()) {
2781 syncSet(dstObj, srcObj);
2782 return;
2783 }
2784
2785 if (dstObj.type().isMap()) {
2786 syncMap(dstObj, srcObj);
2787 return;
2788 }
2789
2790 if (dstObj.type().isPointer()) {
2791 syncPointer(dstObj, srcObj);
2792 return;
2793 }
2794
2795 assert(dstObj.type().isClass());
2796 for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
2797 const Member& srcMember = srcObj.members()[iMember];
2798 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
2799 if (!dstMember)
2800 throw Exception("Expected member missing in destination object");
2801 syncMember(dstMember, srcMember);
2802 }
2803 }
2804
2805 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2806 Member dstMember = dstObj.memberNamed(srcMember.name());
2807 if (dstMember)
2808 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2809 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2810 if (members.size() <= 0)
2811 return Member();
2812 if (members.size() == 1)
2813 return members[0];
2814 for (int i = 0; i < members.size(); ++i)
2815 if (members[i].offset() == srcMember.offset())
2816 return members[i];
2817 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2818 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2819 for (int i = 0; i < members.size(); ++i) {
2820 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2821 if (dstSeqNr == srcSeqNr)
2822 return members[i];
2823 }
2824 return Member(); // give up!
2825 }
2826
2827 void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
2828 assert(dstMember && srcMember);
2829 assert(dstMember.type() == srcMember.type());
2830 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
2831 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
2832 syncObject(dstObj, srcObj);
2833 }
2834
2835 // *************** Exception ***************
2836 // *
2837
2838 Exception::Exception() {
2839 }
2840
2841 Exception::Exception(String format, ...) {
2842 va_list arg;
2843 va_start(arg, format);
2844 Message = assemble(format, arg);
2845 va_end(arg);
2846 }
2847
2848 Exception::Exception(String format, va_list arg) {
2849 Message = assemble(format, arg);
2850 }
2851
2858 std::cout << "Serialization::Exception: " << Message << std::endl;
2859 }
2860
2861 String Exception::assemble(String format, va_list arg) {
2862 char* buf = NULL;
2863 vasprintf(&buf, format.c_str(), arg);
2864 String s = buf;
2865 free(buf);
2866 return s;
2867 }
2868
2869} // namespace Serialization
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
Object & objectByBaseUID(const UID &uid)
Find true object for a base pointer.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
Object & parentObjectOf(const Object &obj)
Access parent of supplied object.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
String internalID() const
Unique key for native data type, for internal purposes only.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Object newInstance(Archive *archive) const
Allocate and initialize a native instance of data type.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage() const
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
UID parentUID() const
Unique identifier of parent object.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
UID parentUID() const
Unique identifier of parent object.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
Definition gig.h:98
void * ID
Abstract identifier for serialized C++ objects.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
std::string String
Textual string.
uint32_t Version
Version number data type.
std::vector< UID > UIDChain
Chain of UIDs.
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
time_base_t
To which time zone a certain timing information relates to.
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...