libgig 4.3.0
Serialization.cpp
1/***************************************************************************
2 * *
3 * Copyright (C) 2017-2020 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 <stdlib.h> // for atof()
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 // *************** DataType ***************
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
83 m_size = 0;
84 m_isPointer = false;
85 }
86
114 DataType::DataType(bool isPointer, int size, String baseType,
115 String customType1, String customType2)
116 {
117 m_size = size;
118 m_isPointer = isPointer;
119 m_baseTypeName = baseType;
120 m_customTypeName = customType1;
121 m_customTypeName2 = customType2;
122 }
123
134 bool DataType::isValid() const {
135 return m_size;
136 }
137
143 bool DataType::isPointer() const {
144 return m_isPointer;
145 }
146
172 bool DataType::isClass() const {
173 return m_baseTypeName == "class";
174 }
175
197 return !isClass() && !isArray() && !isSet() && !isMap();
198 }
199
210 bool DataType::isString() const {
211 return m_baseTypeName == "String";
212 }
213
228 bool DataType::isInteger() const {
229 return m_baseTypeName.substr(0, 3) == "int" ||
230 m_baseTypeName.substr(0, 4) == "uint";
231 }
232
245 bool DataType::isReal() const {
246 return m_baseTypeName.substr(0, 4) == "real";
247 }
248
260 bool DataType::isBool() const {
261 return m_baseTypeName == "bool";
262 }
263
275 bool DataType::isEnum() const {
276 return m_baseTypeName == "enum";
277 }
278
291 bool DataType::isArray() const {
292 return m_baseTypeName == "Array";
293 }
294
307 bool DataType::isSet() const {
308 return m_baseTypeName == "Set";
309 }
310
323 bool DataType::isMap() const {
324 return m_baseTypeName == "Map";
325 }
326
340 bool DataType::isSigned() const {
341 return m_baseTypeName.substr(0, 3) == "int" ||
342 isReal();
343 }
344
363 bool DataType::operator==(const DataType& other) const {
364 return m_baseTypeName == other.m_baseTypeName &&
365 m_customTypeName == other.m_customTypeName &&
366 m_customTypeName2 == other.m_customTypeName2 &&
367 (m_size == other.m_size || (isClass() && other.isClass())) &&
368 m_isPointer == other.m_isPointer;
369 }
370
376 bool DataType::operator!=(const DataType& other) const {
377 return !operator==(other);
378 }
379
391 bool DataType::operator<(const DataType& other) const {
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)))))));
401 }
402
414 bool DataType::operator>(const DataType& other) const {
415 return !(operator==(other) || operator<(other));
416 }
417
432 String DataType::asLongDescr() const {
433 String s = m_baseTypeName;
434 if (!m_customTypeName.empty())
435 s += " " + customTypeName(true);
436 if (!m_customTypeName2.empty())
437 s += " " + customTypeName2(true);
438 if (isPointer())
439 s += " pointer";
440 return s;
441 }
442
472 String DataType::baseTypeName() const {
473 return m_baseTypeName;
474 }
475
476 static String _demangleTypeName(const char* name) {
477#ifdef _MSC_VER
478 const size_t MAXLENGTH = 1024;
479 char result[MAXLENGTH];
480
481 //FIXME: calling UnDecorateSymbolName() is not thread safe!
482 //Skip the first char
483 size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
484 if (size)
485 {
486 return result;
487 }
488 return name;
489#else
490 int status;
491 char* result =
492 abi::__cxa_demangle(name, 0, 0, &status);
493 String sResult = result;
494 free(result);
495 return (status == 0) ? sResult : name;
496#endif
497 }
498
535 String DataType::customTypeName(bool demangle) const {
536 if (!demangle) return m_customTypeName;
537 return _demangleTypeName(m_customTypeName.c_str());
538 }
539
547 String DataType::customTypeName2(bool demangle) const {
548 if (!demangle) return m_customTypeName2;
549 return _demangleTypeName(m_customTypeName2.c_str());
550 }
551
552 // *************** Member ***************
553 // *
554
568 m_uid = NO_UID;
569 m_offset = 0;
570 }
571
572 Member::Member(String name, UID uid, ssize_t offset, DataType type) {
573 m_name = name;
574 m_uid = uid;
575 m_offset = offset;
576 m_type = type;
577 }
578
593 UID Member::uid() const {
594 return m_uid;
595 }
596
617 String Member::name() const {
618 return m_name;
619 }
620
662 ssize_t Member::offset() const {
663 return m_offset;
664 }
665
670 const DataType& Member::type() const {
671 return m_type;
672 }
673
684 bool Member::isValid() const {
685 return m_uid && !m_name.empty() && m_type;
686 }
687
696 bool Member::operator==(const Member& other) const {
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;
701 }
702
708 bool Member::operator!=(const Member& other) const {
709 return !operator==(other);
710 }
711
724 bool Member::operator<(const Member& other) const {
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)))));
732 }
733
746 bool Member::operator>(const Member& other) const {
747 return !(operator==(other) || operator<(other));
748 }
749
750 // *************** Object ***************
751 // *
752
765 m_version = 0;
766 m_minVersion = 0;
767 }
768
787 m_type = type;
788 m_uid = uidChain;
789 m_version = 0;
790 m_minVersion = 0;
791 //m_data.resize(type.size());
792 }
793
804 bool Object::isValid() const {
805 return m_type && !m_uid.empty();
806 }
807
819 UID Object::uid(int index) const {
820 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
821 }
822
823 static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
824 if (type.isPrimitive() && !type.isPointer()) {
825 if (type.isInteger() || type.isEnum()) {
826 if (type.isSigned()) {
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);
835 else
836 assert(false /* unknown signed int type size */);
837 } else {
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);
846 else
847 assert(false /* unknown unsigned int type size */);
848 }
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);
854 else
855 assert(false /* unknown floating point type */);
856 } else if (type.isBool()) {
857 String lower = toLowerCase(s);
858 const bool b = lower != "0" && lower != "false" && lower != "no";
859 *(bool*)ptr = b;
860 } else if (type.isString()) {
861 *(String*)ptr = s;
862 } else {
863 assert(false /* no built-in cast from string support for this data type */);
864 }
865 }
866 }
867
883 void Object::setNativeValueFromString(const String& s) {
884 const ID& id = uid().id;
885 void* ptr = (void*)id;
886 _setNativeValueFromString(ptr, m_type, s.c_str());
887 }
888
895 const UIDChain& Object::uidChain() const {
896 return m_uid;
897 }
898
904 const DataType& Object::type() const {
905 return m_type;
906 }
907
930 const RawData& Object::rawData() const {
931 return m_data;
932 }
933
945 return m_version;
946 }
947
960 return m_minVersion;
961 }
962
995 std::vector<Member>& Object::members() {
996 return m_members;
997 }
998
1005 const std::vector<Member>& Object::members() const {
1006 return m_members;
1007 }
1008
1019 bool Object::operator==(const Object& other) const {
1020 // ignoring all other member variables here
1021 // (since UID stands for "unique" ;-) )
1022 return m_uid == other.m_uid &&
1023 m_type == other.m_type;
1024 }
1025
1031 bool Object::operator!=(const Object& other) const {
1032 return !operator==(other);
1033 }
1034
1047 bool Object::operator<(const Object& other) const {
1048 // ignoring all other member variables here
1049 // (since UID stands for "unique" ;-) )
1050 return m_uid < other.m_uid ||
1051 (m_uid == other.m_uid &&
1052 m_type < other.m_type);
1053 }
1054
1067 bool Object::operator>(const Object& other) const {
1068 return !(operator==(other) || operator<(other));
1069 }
1070
1089 bool Object::isVersionCompatibleTo(const Object& other) const {
1090 if (this->version() == other.version())
1091 return true;
1092 if (this->version() > other.version())
1093 return this->minVersion() <= other.version();
1094 else
1095 return other.minVersion() <= this->version();
1096 }
1097
1098 void Object::setVersion(Version v) {
1099 m_version = v;
1100 }
1101
1102 void Object::setMinVersion(Version v) {
1103 m_minVersion = v;
1104 }
1105
1135 Member Object::memberNamed(String name) const {
1136 for (int i = 0; i < m_members.size(); ++i)
1137 if (m_members[i].name() == name)
1138 return m_members[i];
1139 return Member();
1140 }
1141
1156 Member Object::memberByUID(const UID& uid) const {
1157 if (!uid) return Member();
1158 for (int i = 0; i < m_members.size(); ++i)
1159 if (m_members[i].uid() == uid)
1160 return m_members[i];
1161 return Member();
1162 }
1163
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);
1168 return;
1169 }
1170 }
1171 }
1172
1188 std::vector<Member> Object::membersOfType(const DataType& type) const {
1189 std::vector<Member> v;
1190 for (int i = 0; i < m_members.size(); ++i) {
1191 const Member& member = m_members[i];
1192 if (member.type() == type)
1193 v.push_back(member);
1194 }
1195 return v;
1196 }
1197
1229 int Object::sequenceIndexOf(const Member& member) const {
1230 for (int i = 0; i < m_members.size(); ++i)
1231 if (m_members[i] == member)
1232 return i;
1233 return -1;
1234 }
1235
1236 // *************** Archive ***************
1237 // *
1238
1258 m_operation = OPERATION_NONE;
1259 m_root = NO_UID;
1260 m_isModified = false;
1261 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1262 }
1263
1280 m_operation = OPERATION_NONE;
1281 m_root = NO_UID;
1282 m_isModified = false;
1283 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1284 decode(data);
1285 }
1286
1307 Archive::Archive(const uint8_t* data, size_t size) {
1308 m_operation = OPERATION_NONE;
1309 m_root = NO_UID;
1310 m_isModified = false;
1311 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1312 decode(data, size);
1313 }
1314
1315 Archive::~Archive() {
1316 }
1317
1329 return m_allObjects[m_root];
1330 }
1331
1332 static String _encodeBlob(String data) {
1333 return ToString(data.length()) + ":" + data;
1334 }
1335
1336 static String _encode(const UID& uid) {
1337 String s;
1338 s += _encodeBlob(ToString(size_t(uid.id)));
1339 s += _encodeBlob(ToString(size_t(uid.size)));
1340 return _encodeBlob(s);
1341 }
1342
1343 static String _encode(const time_t& time) {
1344 return _encodeBlob(ToString(time));
1345 }
1346
1347 static String _encode(const DataType& type) {
1348 String s;
1349
1350 // Srx v1.0 format (mandatory):
1351 s += _encodeBlob(type.baseTypeName());
1352 s += _encodeBlob(type.customTypeName());
1353 s += _encodeBlob(ToString(type.size()));
1354 s += _encodeBlob(ToString(type.isPointer()));
1355
1356 // Srx v1.1 format:
1357 s += _encodeBlob(type.customTypeName2());
1358
1359 return _encodeBlob(s);
1360 }
1361
1362 static String _encode(const UIDChain& chain) {
1363 String s;
1364 for (int i = 0; i < chain.size(); ++i)
1365 s += _encode(chain[i]);
1366 return _encodeBlob(s);
1367 }
1368
1369 static String _encode(const Member& member) {
1370 String s;
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);
1376 }
1377
1378 static String _encode(const std::vector<Member>& members) {
1379 String s;
1380 for (int i = 0; i < members.size(); ++i)
1381 s += _encode(members[i]);
1382 return _encodeBlob(s);
1383 }
1384
1385 static String _primitiveObjectValueToString(const Object& obj) {
1386 String s;
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); // int16_t: prevent ToString() to render an ASCII character
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);
1403 else
1404 assert(false /* unknown signed int type size */);
1405 } else {
1406 if (type.size() == 1)
1407 s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
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);
1414 else
1415 assert(false /* unknown unsigned int type size */);
1416 }
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);
1422 else
1423 assert(false /* unknown floating point type */);
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);
1428 } else {
1429 assert(false /* unknown primitive type */);
1430 }
1431 }
1432 return s;
1433 }
1434
1435 template<typename T>
1436 inline T _stringToNumber(const String& s) {
1437 assert(false /* String cast to unknown primitive number type */);
1438 }
1439
1440 template<>
1441 inline int64_t _stringToNumber(const String& s) {
1442 return atoll(s.c_str());
1443 }
1444
1445 template<>
1446 inline double _stringToNumber(const String& s) {
1447 return atof(s.c_str());
1448 }
1449
1450 template<>
1451 inline bool _stringToNumber(const String& s) {
1452 return (bool) atoll(s.c_str());
1453 }
1454
1455 template<typename T>
1456 static T _primitiveObjectValueToNumber(const Object& obj) {
1457 T value = 0;
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;
1474 else
1475 assert(false /* unknown signed int type size */);
1476 } else {
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;
1485 else
1486 assert(false /* unknown unsigned int type size */);
1487 }
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;
1493 else
1494 assert(false /* unknown floating point type */);
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)
1500 );
1501 } else {
1502 assert(false /* unknown primitive type */);
1503 }
1504 }
1505 return value;
1506 }
1507
1508 static String _encodePrimitiveValue(const Object& obj) {
1509 return _encodeBlob( _primitiveObjectValueToString(obj) );
1510 }
1511
1512 static String _encode(const Object& obj) {
1513 String s;
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);
1521 }
1522
1523 String _encode(const Archive::ObjectPool& objects) {
1524 String s;
1525 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
1526 itObject != objects.end(); ++itObject)
1527 {
1528 const Object& obj = itObject->second;
1529 s += _encode(obj);
1530 }
1531 return _encodeBlob(s);
1532 }
1533
1534 /*
1535 * Srx format history:
1536 * - 1.0: Initial version.
1537 * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1538 * 2nd custom type name (e.g. "Map" types which always contain two
1539 * user defined types).
1540 */
1541 #define MAGIC_START "Srx1v"
1542 #define ENCODING_FORMAT_MINOR_VERSION 1
1543
1544 String Archive::_encodeRootBlob() {
1545 String s;
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);
1554 }
1555
1556 void Archive::encode() {
1557 m_rawData.clear();
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;
1566 }
1567
1568 struct _Blob {
1569 const char* p;
1570 const char* end;
1571 };
1572
1573 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1574 if (!bThrow && p >= end) {
1575 const _Blob blob = { p, end };
1576 return blob;
1577 }
1578 size_t sz = 0;
1579 for (; true; ++p) {
1580 if (p >= end)
1581 throw Exception("Decode Error: Missing blob");
1582 const char& c = *p;
1583 if (c == ':') break;
1584 if (c < '0' || c > '9')
1585 throw Exception("Decode Error: Missing blob size");
1586 sz *= 10;
1587 sz += size_t(c - '0');
1588 }
1589 ++p;
1590 if (p + sz > end)
1591 throw Exception("Decode Error: Premature end of blob");
1592 const _Blob blob = { p, p + sz };
1593 return blob;
1594 }
1595
1596 template<typename T_int>
1597 static T_int _popIntBlob(const char*& p, const char* end) {
1598 _Blob blob = _decodeBlob(p, end);
1599 p = blob.p;
1600 end = blob.end;
1601
1602 T_int sign = 1;
1603 T_int i = 0;
1604 if (p >= end)
1605 throw Exception("Decode Error: premature end of int blob");
1606 if (*p == '-') {
1607 sign = -1;
1608 ++p;
1609 }
1610 for (; p < end; ++p) {
1611 const char& c = *p;
1612 if (c < '0' || c > '9')
1613 throw Exception("Decode Error: Invalid int blob format");
1614 i *= 10;
1615 i += size_t(c - '0');
1616 }
1617 return i * sign;
1618 }
1619
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;
1624 }
1625
1626 template<typename T_real>
1627 static T_real _popRealBlob(const char*& p, const char* end) {
1628 _Blob blob = _decodeBlob(p, end);
1629 p = blob.p;
1630 end = blob.end;
1631
1632 if (p >= end || (end - p) < 1)
1633 throw Exception("Decode Error: premature end of real blob");
1634
1635 String s(p, size_t(end - p));
1636
1637 T_real r;
1638 if (sizeof(T_real) <= sizeof(double))
1639 r = atof(s.c_str());
1640 else
1641 assert(false /* unknown real type */);
1642
1643 p += s.length();
1644
1645 return r;
1646 }
1647
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;
1652 }
1653
1654 static String _popStringBlob(const char*& p, const char* end) {
1655 _Blob blob = _decodeBlob(p, end);
1656 p = blob.p;
1657 end = blob.end;
1658 if (end - p < 0)
1659 throw Exception("Decode Error: missing String blob");
1660 String s;
1661 const size_t sz = end - p;
1662 s.resize(sz);
1663 memcpy(&s[0], p, sz);
1664 p += sz;
1665 return s;
1666 }
1667
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]);
1672 }
1673
1674 static time_t _popTimeBlob(const char*& p, const char* end) {
1675 const uint64_t i = _popIntBlob<uint64_t>(p, end);
1676 return (time_t) i;
1677 }
1678
1679 static DataType _popDataTypeBlob(const char*& p, const char* end) {
1680 _Blob blob = _decodeBlob(p, end);
1681 p = blob.p;
1682 end = blob.end;
1683
1684 DataType type;
1685
1686 // Srx v1.0 format (mandatory):
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);
1691
1692 // Srx v1.1 format (optional):
1693 if (p < end)
1694 type.m_customTypeName2 = _popStringBlob(p, end);
1695
1696 return type;
1697 }
1698
1699 static UID _popUIDBlob(const char*& p, const char* end) {
1700 _Blob blob = _decodeBlob(p, end);
1701 p = blob.p;
1702 end = blob.end;
1703
1704 if (p >= end)
1705 throw Exception("Decode Error: premature end of UID blob");
1706
1707 const ID id = (ID) _popIntBlob<size_t>(p, end);
1708 const size_t size = _popIntBlob<size_t>(p, end);
1709
1710 const UID uid = { id, size };
1711 return uid;
1712 }
1713
1714 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
1715 _Blob blob = _decodeBlob(p, end);
1716 p = blob.p;
1717 end = blob.end;
1718
1719 UIDChain chain;
1720 while (p < end) {
1721 const UID uid = _popUIDBlob(p, end);
1722 chain.push_back(uid);
1723 }
1724 assert(!chain.empty());
1725 return chain;
1726 }
1727
1728 static Member _popMemberBlob(const char*& p, const char* end) {
1729 _Blob blob = _decodeBlob(p, end, false);
1730 p = blob.p;
1731 end = blob.end;
1732
1733 Member m;
1734 if (p >= end) return m;
1735
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);
1740 assert(m.type());
1741 assert(!m.name().empty());
1742 assert(m.uid().isValid());
1743 return m;
1744 }
1745
1746 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
1747 _Blob blob = _decodeBlob(p, end, false);
1748 p = blob.p;
1749 end = blob.end;
1750
1751 std::vector<Member> members;
1752 while (p < end) {
1753 const Member member = _popMemberBlob(p, end);
1754 if (member)
1755 members.push_back(member);
1756 else
1757 break;
1758 }
1759 return members;
1760 }
1761
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);
1776 else
1777 assert(false /* unknown signed int type size */);
1778 } else {
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);
1787 else
1788 assert(false /* unknown unsigned int type size */);
1789 }
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);
1795 else
1796 assert(false /* unknown floating point type */);
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);
1801 } else {
1802 assert(false /* unknown primitive type */);
1803 }
1804
1805 } else {
1806 // don't whine if the empty blob was not added on encoder side
1807 _Blob blob = _decodeBlob(p, end, false);
1808 p = blob.p;
1809 end = blob.end;
1810 }
1811 }
1812
1813 static Object _popObjectBlob(const char*& p, const char* end) {
1814 _Blob blob = _decodeBlob(p, end, false);
1815 p = blob.p;
1816 end = blob.end;
1817
1818 Object obj;
1819 if (p >= end) return obj;
1820
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);
1827 assert(obj.type());
1828 return obj;
1829 }
1830
1831 void Archive::_popObjectsBlob(const char*& p, const char* end) {
1832 _Blob blob = _decodeBlob(p, end, false);
1833 p = blob.p;
1834 end = blob.end;
1835
1836 if (p >= end)
1837 throw Exception("Decode Error: Premature end of objects blob");
1838
1839 while (true) {
1840 const Object obj = _popObjectBlob(p, end);
1841 if (!obj) break;
1842 m_allObjects[obj.uid()] = obj;
1843 }
1844 }
1845
1846 void Archive::_popRootBlob(const char*& p, const char* end) {
1847 _Blob blob = _decodeBlob(p, end, false);
1848 p = blob.p;
1849 end = blob.end;
1850
1851 if (p >= end)
1852 throw Exception("Decode Error: Premature end of root blob");
1853
1854 // just in case this encoding format will be extended in future
1855 // (currently not used)
1856 const int formatMinorVersion = _popIntBlob<int>(p, end);
1857
1858 m_root = _popUIDBlob(p, end);
1859 if (!m_root)
1860 throw Exception("Decode Error: No root object");
1861
1862 _popObjectsBlob(p, end);
1863 if (!m_allObjects[m_root])
1864 throw Exception("Decode Error: Missing declared root object");
1865
1866 m_name = _popStringBlob(p, end);
1867 m_comment = _popStringBlob(p, end);
1868 m_timeCreated = _popTimeBlob(p, end);
1869 m_timeModified = _popTimeBlob(p, end);
1870 }
1871
1887 void Archive::decode(const RawData& data) {
1888 m_rawData = data;
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);
1898 }
1899
1920 void Archive::decode(const uint8_t* data, size_t size) {
1921 RawData rawData;
1922 rawData.resize(size);
1923 memcpy(&rawData[0], data, size);
1924 decode(rawData);
1925 }
1926
1942 const RawData& Archive::rawData() {
1943 if (m_isModified) encode();
1944 return m_rawData;
1945 }
1946
1952 String Archive::rawDataFormat() const {
1953 return MAGIC_START;
1954 }
1955
1970 bool Archive::isModified() const {
1971 return m_isModified;
1972 }
1973
1979 void Archive::clear() {
1980 m_allObjects.clear();
1981 m_operation = OPERATION_NONE;
1982 m_root = NO_UID;
1983 m_rawData.clear();
1984 m_isModified = false;
1985 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1986 }
1987
1995 String Archive::name() const {
1996 return m_name;
1997 }
1998
2008 void Archive::setName(String name) {
2009 if (m_name == name) return;
2010 m_name = name;
2011 m_isModified = true;
2012 }
2013
2021 String Archive::comment() const {
2022 return m_comment;
2023 }
2024
2034 void Archive::setComment(String comment) {
2035 if (m_comment == comment) return;
2036 m_comment = comment;
2037 m_isModified = true;
2038 }
2039
2040 static tm _convertTimeStamp(const time_t& time, time_base_t base) {
2041 tm* pTm;
2042 switch (base) {
2043 case LOCAL_TIME:
2044 pTm = localtime(&time);
2045 break;
2046 case UTC_TIME:
2047 pTm = gmtime(&time);
2048 break;
2049 default:
2050 throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
2051 }
2052 if (!pTm)
2053 throw Exception("Failed assembling time stamp structure");
2054 return *pTm;
2055 }
2056
2062 time_t Archive::timeStampCreated() const {
2063 return m_timeCreated;
2064 }
2065
2071 time_t Archive::timeStampModified() const {
2072 return m_timeModified;
2073 }
2074
2085 tm Archive::dateTimeCreated(time_base_t base) const {
2086 return _convertTimeStamp(m_timeCreated, base);
2087 }
2088
2099 tm Archive::dateTimeModified(time_base_t base) const {
2100 return _convertTimeStamp(m_timeModified, base);
2101 }
2102
2120 void Archive::removeMember(Object& parent, const Member& member) {
2121 parent.remove(member);
2122 m_isModified = true;
2123 }
2124
2140 void Archive::remove(const Object& obj) {
2141 //FIXME: Should traverse from root object and remove all members associated with this object
2142 if (!obj.uid()) return;
2143 m_allObjects.erase(obj.uid());
2144 m_isModified = true;
2145 }
2146
2158 Object& Archive::objectByUID(const UID& uid) {
2159 return m_allObjects[uid];
2160 }
2161
2172 void Archive::setVersion(Object& object, Version v) {
2173 if (!object) return;
2174 object.setVersion(v);
2175 m_isModified = true;
2176 }
2177
2188 void Archive::setMinVersion(Object& object, Version v) {
2189 if (!object) return;
2190 object.setMinVersion(v);
2191 m_isModified = true;
2192 }
2193
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));
2209 if (!obj) return;
2210 pObject = &obj;
2211 }
2212 const int nativeEnumSize = sizeof(enum operation_t);
2213 DataType& type = const_cast<DataType&>( pObject->type() );
2214 // original serializer ("sender") might have had a different word size
2215 // than this machine, adjust type object in this case
2216 if (type.size() != nativeEnumSize) {
2217 type.m_size = nativeEnumSize;
2218 }
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;
2229 else
2230 assert(false /* unknown enum type size */);
2231 m_isModified = true;
2232 }
2233
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));
2251 if (!obj) return;
2252 pObject = &obj;
2253 }
2254 const DataType& type = pObject->type();
2255 pObject->m_data.resize(type.size());
2256 void* ptr = &pObject->m_data[0];
2257 if (type.isSigned()) {
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;
2266 else
2267 assert(false /* unknown signed int type size */);
2268 } else {
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;
2277 else
2278 assert(false /* unknown unsigned int type size */);
2279 }
2280 m_isModified = true;
2281 }
2282
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));
2301 if (!obj) return;
2302 pObject = &obj;
2303 }
2304 const DataType& type = pObject->type();
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;
2311 else
2312 assert(false /* unknown real type size */);
2313 m_isModified = true;
2314 }
2315
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));
2331 if (!obj) return;
2332 pObject = &obj;
2333 }
2334 const DataType& type = pObject->type();
2335 pObject->m_data.resize(type.size());
2336 bool* ptr = (bool*)&pObject->m_data[0];
2337 *ptr = value;
2338 m_isModified = true;
2339 }
2340
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));
2356 if (!obj) return;
2357 pObject = &obj;
2358 }
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;
2363 }
2364
2378 void Archive::setAutoValue(Object& object, String value) {
2379 if (!object) return;
2380 const DataType& type = object.type();
2381 if (type.isInteger())
2382 setIntValue(object, atoll(value.c_str()));
2383 else if (type.isReal())
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);
2391 else
2392 setBoolValue(object, atof(value.c_str()));
2393 } else if (type.isString())
2394 setStringValue(object, value);
2395 else if (type.isEnum())
2396 setEnumValue(object, atoll(value.c_str()));
2397 else
2398 throw Exception("Not a primitive data type");
2399 }
2400
2410 String Archive::valueAsString(const Object& object) {
2411 if (!object)
2412 throw Exception("Invalid 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 "";
2419 pObject = &obj;
2420 }
2421 return _primitiveObjectValueToString(*pObject);
2422 }
2423
2433 int64_t Archive::valueAsInt(const Object& object) {
2434 if (!object)
2435 throw Exception("Invalid 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));
2441 if (!obj) return 0;
2442 pObject = &obj;
2443 }
2444 return _primitiveObjectValueToNumber<int64_t>(*pObject);
2445 }
2446
2456 double Archive::valueAsReal(const Object& object) {
2457 if (!object)
2458 throw Exception("Invalid 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));
2464 if (!obj) return 0;
2465 pObject = &obj;
2466 }
2467 return _primitiveObjectValueToNumber<double>(*pObject);
2468 }
2469
2478 bool Archive::valueAsBool(const Object& object) {
2479 if (!object)
2480 throw Exception("Invalid 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));
2486 if (!obj) return 0;
2487 pObject = &obj;
2488 }
2489 return _primitiveObjectValueToNumber<bool>(*pObject);
2490 }
2491
2492 Archive::operation_t Archive::operation() const {
2493 return m_operation;
2494 }
2495
2496 // *************** Archive::Syncer ***************
2497 // *
2498
2499 Archive::Syncer::Syncer(Archive& dst, Archive& src)
2500 : m_dst(dst), m_src(src)
2501 {
2502 const Object srcRootObj = src.rootObject();
2503 const Object dstRootObj = dst.rootObject();
2504 if (!srcRootObj)
2505 throw Exception("No source root object!");
2506 if (!dstRootObj)
2507 throw Exception("Expected destination root object not found!");
2508 syncObject(dstRootObj, srcRootObj);
2509 }
2510
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());
2515 }
2516
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];
2522 }
2523
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);
2528 }
2529
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);
2534 }
2535
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);
2540 }
2541
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);
2548 }
2549
2550 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
2551 if (!dstObj || !srcObj) return; // end of recursion
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() + ")");
2562
2563 // prevent syncing this object again, and thus also prevent endless
2564 // loop on data structures with cyclic relations
2565 m_dst.m_allObjects.erase(dstObj.uid());
2566
2567 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2568 if (dstObj.type().isString())
2569 syncString(dstObj, srcObj);
2570 else
2571 syncPrimitive(dstObj, srcObj);
2572 return; // end of recursion
2573 }
2574
2575 if (dstObj.type().isArray()) {
2576 syncArray(dstObj, srcObj);
2577 return;
2578 }
2579
2580 if (dstObj.type().isSet()) {
2581 syncSet(dstObj, srcObj);
2582 return;
2583 }
2584
2585 if (dstObj.type().isMap()) {
2586 syncMap(dstObj, srcObj);
2587 return;
2588 }
2589
2590 if (dstObj.type().isPointer()) {
2591 syncPointer(dstObj, srcObj);
2592 return;
2593 }
2594
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);
2599 if (!dstMember)
2600 throw Exception("Expected member missing in destination object");
2601 syncMember(dstMember, srcMember);
2602 }
2603 }
2604
2605 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
2606 Member dstMember = dstObj.memberNamed(srcMember.name());
2607 if (dstMember)
2608 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
2609 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
2610 if (members.size() <= 0)
2611 return Member();
2612 if (members.size() == 1)
2613 return members[0];
2614 for (int i = 0; i < members.size(); ++i)
2615 if (members[i].offset() == srcMember.offset())
2616 return members[i];
2617 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
2618 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
2619 for (int i = 0; i < members.size(); ++i) {
2620 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
2621 if (dstSeqNr == srcSeqNr)
2622 return members[i];
2623 }
2624 return Member(); // give up!
2625 }
2626
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);
2633 }
2634
2635 // *************** Exception ***************
2636 // *
2637
2638 Exception::Exception() {
2639 }
2640
2641 Exception::Exception(String format, ...) {
2642 va_list arg;
2643 va_start(arg, format);
2644 Message = assemble(format, arg);
2645 va_end(arg);
2646 }
2647
2648 Exception::Exception(String format, va_list arg) {
2649 Message = assemble(format, arg);
2650 }
2651
2658 std::cout << "Serialization::Exception: " << Message << std::endl;
2659 }
2660
2661 String Exception::assemble(String format, va_list arg) {
2662 char* buf = NULL;
2663 vasprintf(&buf, format.c_str(), arg);
2664 String s = buf;
2665 free(buf);
2666 return s;
2667 }
2668
2669} // namespace Serialization
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.
Definition RIFF.h:157
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.
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...