/[svn]/libgig/trunk/src/Serialization.cpp
ViewVC logotype

Contents of /libgig/trunk/src/Serialization.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3138 - (show annotations) (download)
Wed May 3 14:41:58 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 27977 byte(s)
* Added new "Serialization" framework (and equally named namespace)
  which allows to serialize and deserialize native C++ objects
  in a portable, easy and flexible way.
* gig.cpp/gig.h: Added support for serializing & deserializing
  DimensionRegion objects (and crossfade_t and leverage_ctrl_t
  objects).
* Bumped version (4.0.0.svn15).

1 /***************************************************************************
2 * *
3 * Copyright (C) 2017 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 #include "Serialization.h"
25
26 #include <iostream>
27 #include <assert.h>
28 #include <string.h> // for memcpy()
29 #include <stdlib.h> // for atof() and atof_l()
30 #include <xlocale.h> // for locale passed to atof_l()
31
32 #include "helper.h"
33
34 namespace Serialization {
35
36 // *************** DataType ***************
37 // *
38
39 static UID _createNullUID() {
40 return (UID) { NULL, 0 };
41 }
42
43 const UID NO_UID = _createNullUID();
44
45 bool UID::isValid() const {
46 return id != NULL && id != (void*)-1 && size;
47 }
48
49 // *************** DataType ***************
50 // *
51
52 DataType::DataType() {
53 m_size = 0;
54 m_isPointer = false;
55 }
56
57 DataType::DataType(bool isPointer, int size, String baseType, String customType) {
58 m_size = size;
59 m_isPointer = isPointer;
60 m_baseTypeName = baseType;
61 m_customTypeName = customType;
62 }
63
64 bool DataType::isValid() const {
65 return m_size;
66 }
67
68 bool DataType::isPointer() const {
69 return m_isPointer;
70 }
71
72 bool DataType::isClass() const {
73 return m_baseTypeName == "class";
74 }
75
76 bool DataType::isPrimitive() const {
77 return !isClass();
78 }
79
80 bool DataType::isInteger() const {
81 return m_baseTypeName.substr(0, 3) == "int" ||
82 m_baseTypeName.substr(0, 4) == "uint";
83 }
84
85 bool DataType::isReal() const {
86 return m_baseTypeName.substr(0, 4) == "real";
87 }
88
89 bool DataType::isBool() const {
90 return m_baseTypeName == "bool";
91 }
92
93 bool DataType::isEnum() const {
94 return m_baseTypeName == "enum";
95 }
96
97 bool DataType::isSigned() const {
98 return m_baseTypeName.substr(0, 3) == "int" ||
99 isReal();
100 }
101
102 bool DataType::operator==(const DataType& other) const {
103 return m_baseTypeName == other.m_baseTypeName &&
104 m_customTypeName == other.m_customTypeName &&
105 m_size == other.m_size &&
106 m_isPointer == other.m_isPointer;
107 }
108
109 bool DataType::operator!=(const DataType& other) const {
110 return !operator==(other);
111 }
112
113 bool DataType::operator<(const DataType& other) const {
114 return m_baseTypeName < other.m_baseTypeName ||
115 (m_baseTypeName == other.m_baseTypeName &&
116 m_customTypeName < other.m_customTypeName ||
117 (m_customTypeName == other.m_customTypeName &&
118 m_size < other.m_size ||
119 (m_size == other.m_size &&
120 m_isPointer < other.m_isPointer)));
121 }
122
123 bool DataType::operator>(const DataType& other) const {
124 return !(operator==(other) || operator<(other));
125 }
126
127 String DataType::asLongDescr() const {
128 //TODO: Demangling of C++ raw type names
129 String s = m_baseTypeName;
130 if (!m_customTypeName.empty())
131 s += " " + m_customTypeName;
132 if (isPointer())
133 s += " pointer";
134 return s;
135 }
136
137 // *************** Member ***************
138 // *
139
140 Member::Member() {
141 m_uid = NO_UID;
142 m_offset = 0;
143 }
144
145 Member::Member(String name, UID uid, size_t offset, DataType type) {
146 m_name = name;
147 m_uid = uid;
148 m_offset = offset;
149 m_type = type;
150 }
151
152 bool Member::isValid() const {
153 return m_uid && !m_name.empty() && m_type;
154 }
155
156 bool Member::operator==(const Member& other) const {
157 return m_uid == other.m_uid &&
158 m_offset == other.m_offset &&
159 m_name == other.m_name &&
160 m_type == other.m_type;
161 }
162
163 bool Member::operator!=(const Member& other) const {
164 return !operator==(other);
165 }
166
167 bool Member::operator<(const Member& other) const {
168 return m_uid < other.m_uid ||
169 (m_uid == other.m_uid &&
170 m_offset < other.m_offset ||
171 (m_offset == other.m_offset &&
172 m_name < other.m_name ||
173 (m_name == other.m_name &&
174 m_type < other.m_type)));
175 }
176
177 bool Member::operator>(const Member& other) const {
178 return !(operator==(other) || operator<(other));
179 }
180
181 // *************** Object ***************
182 // *
183
184 Object::Object() {
185 m_version = 0;
186 m_minVersion = 0;
187 }
188
189 Object::Object(UIDChain uidChain, DataType type) {
190 m_type = type;
191 m_uid = uidChain;
192 m_version = 0;
193 m_minVersion = 0;
194 m_data.resize(type.size());
195 }
196
197 bool Object::isValid() const {
198 return m_type && !m_uid.empty();
199 }
200
201 bool Object::operator==(const Object& other) const {
202 // ignoring all other member variables here
203 // (since UID stands for "unique" ;-) )
204 return m_uid == other.m_uid &&
205 m_type == other.m_type;
206 }
207
208 bool Object::operator!=(const Object& other) const {
209 return !operator==(other);
210 }
211
212 bool Object::operator<(const Object& other) const {
213 // ignoring all other member variables here
214 // (since UID stands for "unique" ;-) )
215 return m_uid < other.m_uid ||
216 (m_uid == other.m_uid &&
217 m_type < other.m_type);
218 }
219
220 bool Object::operator>(const Object& other) const {
221 return !(operator==(other) || operator<(other));
222 }
223
224 bool Object::isVersionCompatibleTo(const Object& other) const {
225 if (this->version() == other.version())
226 return true;
227 if (this->version() > other.version())
228 return this->minVersion() <= other.version();
229 else
230 return other.minVersion() <= this->version();
231 }
232
233 Member Object::memberNamed(String name) const {
234 for (int i = 0; i < m_members.size(); ++i)
235 if (m_members[i].name() == name)
236 return m_members[i];
237 return Member();
238 }
239
240 void Object::remove(const Member& member) {
241 for (int i = 0; i < m_members.size(); ++i) {
242 if (m_members[i] == member) {
243 m_members.erase(m_members.begin() + i);
244 return;
245 }
246 }
247 }
248
249 std::vector<Member> Object::membersOfType(const DataType& type) const {
250 std::vector<Member> v;
251 for (int i = 0; i < m_members.size(); ++i) {
252 const Member& member = m_members[i];
253 if (member.type() == type)
254 v.push_back(member);
255 }
256 return v;
257 }
258
259 int Object::sequenceIndexOf(const Member& member) const {
260 for (int i = 0; i < m_members.size(); ++i)
261 if (m_members[i] == member)
262 return i;
263 return -1;
264 }
265
266 // *************** Archive ***************
267 // *
268
269 Archive::Archive() {
270 m_operation = OPERATION_NONE;
271 m_root = NO_UID;
272 }
273
274 Archive::Archive(const RawData& data) {
275 m_operation = OPERATION_NONE;
276 m_root = NO_UID;
277 decode(m_rawData);
278 }
279
280 Archive::Archive(const uint8_t* data, size_t size) {
281 m_operation = OPERATION_NONE;
282 m_root = NO_UID;
283 decode(data, size);
284 }
285
286 Archive::~Archive() {
287 }
288
289 Object& Archive::rootObject() {
290 return m_allObjects[m_root];
291 }
292
293 static String _encodeBlob(String data) {
294 return ToString(data.length()) + ":" + data;
295 }
296
297 static String _encode(const UID& uid) {
298 String s;
299 s += _encodeBlob(ToString(size_t(uid.id)));
300 s += _encodeBlob(ToString(size_t(uid.size)));
301 return _encodeBlob(s);
302 }
303
304 static String _encode(const DataType& type) {
305 String s;
306 s += _encodeBlob(type.baseTypeName());
307 s += _encodeBlob(type.customTypeName());
308 s += _encodeBlob(ToString(type.size()));
309 s += _encodeBlob(ToString(type.isPointer()));
310 return _encodeBlob(s);
311 }
312
313 static String _encode(const UIDChain& chain) {
314 String s;
315 for (int i = 0; i < chain.size(); ++i)
316 s += _encode(chain[i]);
317 return _encodeBlob(s);
318 }
319
320 static String _encode(const Member& member) {
321 String s;
322 s += _encode(member.uid());
323 s += _encodeBlob(ToString(member.offset()));
324 s += _encodeBlob(member.name());
325 s += _encode(member.type());
326 return _encodeBlob(s);
327 }
328
329 static String _encode(const std::vector<Member>& members) {
330 String s;
331 for (int i = 0; i < members.size(); ++i)
332 s += _encode(members[i]);
333 return _encodeBlob(s);
334 }
335
336 static String _encodePrimitiveValue(const Object& obj) {
337 String s;
338 const DataType& type = obj.type();
339 const ID& id = obj.uid().id;
340 if (type.isPrimitive() && !type.isPointer()) {
341 if (type.isInteger() || type.isEnum()) {
342 if (type.isSigned()) {
343 if (type.size() == 1)
344 s = ToString((int16_t)*(int8_t*)id); // int16_t: prevent ToString() to render an ASCII character
345 else if (type.size() == 2)
346 s = ToString(*(int16_t*)id);
347 else if (type.size() == 4)
348 s = ToString(*(int32_t*)id);
349 else if (type.size() == 8)
350 s = ToString(*(int64_t*)id);
351 else
352 assert(false /* unknown signed int type size */);
353 } else {
354 if (type.size() == 1)
355 s = ToString((uint16_t)*(uint8_t*)id); // uint16_t: prevent ToString() to render an ASCII character
356 else if (type.size() == 2)
357 s = ToString(*(uint16_t*)id);
358 else if (type.size() == 4)
359 s = ToString(*(uint32_t*)id);
360 else if (type.size() == 8)
361 s = ToString(*(uint64_t*)id);
362 else
363 assert(false /* unknown unsigned int type size */);
364 }
365 } else if (type.isReal()) {
366 if (type.size() == sizeof(float))
367 s = ToString(*(float*)id);
368 else if (type.size() == sizeof(double))
369 s = ToString(*(double*)id);
370 else
371 assert(false /* unknown floating point type */);
372 } else if (type.isBool()) {
373 s = ToString(*(bool*)id);
374 } else {
375 assert(false /* unknown primitive type */);
376 }
377
378 }
379 return _encodeBlob(s);
380 }
381
382 static String _encode(const Object& obj) {
383 String s;
384 s += _encode(obj.type());
385 s += _encodeBlob(ToString(obj.version()));
386 s += _encodeBlob(ToString(obj.minVersion()));
387 s += _encode(obj.uidChain());
388 s += _encode(obj.members());
389 s += _encodePrimitiveValue(obj);
390 return _encodeBlob(s);
391 }
392
393 String _encode(const Archive::ObjectPool& objects) {
394 String s;
395 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
396 itObject != objects.end(); ++itObject)
397 {
398 const Object& obj = itObject->second;
399 s += _encode(obj);
400 }
401 return _encodeBlob(s);
402 }
403
404 #define MAGIC_START "Srx1v"
405 #define ENCODING_FORMAT_MINOR_VERSION 0
406
407 String Archive::_encodeRootBlob() {
408 String s;
409 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
410 s += _encode(m_root);
411 s += _encode(m_allObjects);
412 return _encodeBlob(s);
413 }
414
415 void Archive::encode() {
416 m_rawData.clear();
417 String s = MAGIC_START;
418 s += _encodeRootBlob();
419 m_rawData.resize(s.length() + 1);
420 memcpy(&m_rawData[0], &s[0], s.length() + 1);
421 }
422
423 struct _Blob {
424 const char* p;
425 const char* end;
426 };
427
428 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
429 if (!bThrow && p >= end)
430 return (_Blob) { p, end };
431 size_t sz = 0;
432 for (; true; ++p) {
433 if (p >= end)
434 throw Exception("Decode Error: Missing blob");
435 const char& c = *p;
436 if (c == ':') break;
437 if (c < '0' || c > '9')
438 throw Exception("Decode Error: Missing blob size");
439 sz *= 10;
440 sz += size_t(c - '0');
441 }
442 ++p;
443 if (p + sz > end)
444 throw Exception("Decode Error: Premature end of blob");
445 return (_Blob) { p, p + sz };
446 }
447
448 template<typename T_int>
449 static T_int _popIntBlob(const char*& p, const char* end) {
450 _Blob blob = _decodeBlob(p, end);
451 p = blob.p;
452 end = blob.end;
453
454 T_int sign = 1;
455 T_int i = 0;
456 if (p >= end)
457 throw Exception("Decode Error: premature end of int blob");
458 if (*p == '-') {
459 sign = -1;
460 ++p;
461 }
462 for (; p < end; ++p) {
463 const char& c = *p;
464 if (c < '0' || c > '9')
465 throw Exception("Decode Error: Invalid int blob format");
466 i *= 10;
467 i += size_t(c - '0');
468 }
469 return i * sign;
470 }
471
472 template<typename T_int>
473 static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
474 const T_int i = _popIntBlob<T_int>(p, end);
475 *(T_int*)&rawData[0] = i;
476 }
477
478 template<typename T_real>
479 static T_real _popRealBlob(const char*& p, const char* end) {
480 _Blob blob = _decodeBlob(p, end);
481 p = blob.p;
482 end = blob.end;
483
484 if (p >= end || (end - p) < 1)
485 throw Exception("Decode Error: premature end of real blob");
486
487 String s(p, size_t(end - p));
488
489 T_real r;
490 if (sizeof(T_real) == sizeof(float))
491 r = atof(s.c_str());
492 else if (sizeof(T_real) == sizeof(double))
493 r = atof_l(s.c_str(), _c_locale);
494 else
495 assert(false /* unknown real type */);
496
497 p += s.length();
498
499 return r;
500 }
501
502 template<typename T_real>
503 static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
504 const T_real r = _popRealBlob<T_real>(p, end);
505 *(T_real*)&rawData[0] = r;
506 }
507
508 static String _popStringBlob(const char*& p, const char* end) {
509 _Blob blob = _decodeBlob(p, end);
510 p = blob.p;
511 end = blob.end;
512 if (end - p < 0)
513 throw Exception("Decode Error: missing String blob");
514 String s;
515 const size_t sz = end - p;
516 s.resize(sz);
517 memcpy(&s[0], p, sz);
518 p += sz;
519 return s;
520 }
521
522 DataType _popDataTypeBlob(const char*& p, const char* end) {
523 _Blob blob = _decodeBlob(p, end);
524 p = blob.p;
525 end = blob.end;
526
527 DataType type;
528 type.m_baseTypeName = _popStringBlob(p, end);
529 type.m_customTypeName = _popStringBlob(p, end);
530 type.m_size = _popIntBlob<int>(p, end);
531 type.m_isPointer = _popIntBlob<bool>(p, end);
532 return type;
533 }
534
535 static UID _popUIDBlob(const char*& p, const char* end) {
536 _Blob blob = _decodeBlob(p, end);
537 p = blob.p;
538 end = blob.end;
539
540 if (p >= end)
541 throw Exception("Decode Error: premature end of UID blob");
542
543 const ID id = (ID) _popIntBlob<size_t>(p, end);
544 const size_t size = _popIntBlob<size_t>(p, end);
545
546 return (UID) { id, size };
547 }
548
549 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
550 _Blob blob = _decodeBlob(p, end);
551 p = blob.p;
552 end = blob.end;
553
554 UIDChain chain;
555 while (p < end) {
556 const UID uid = _popUIDBlob(p, end);
557 chain.push_back(uid);
558 }
559 assert(!chain.empty());
560 return chain;
561 }
562
563 Member _popMemberBlob(const char*& p, const char* end) {
564 _Blob blob = _decodeBlob(p, end, false);
565 p = blob.p;
566 end = blob.end;
567
568 Member m;
569 if (p >= end) return m;
570
571 m.m_uid = _popUIDBlob(p, end);
572 m.m_offset = _popIntBlob<size_t>(p, end);
573 m.m_name = _popStringBlob(p, end);
574 m.m_type = _popDataTypeBlob(p, end);
575 assert(m.type());
576 assert(!m.name().empty());
577 assert(m.uid() != NULL);
578 return m;
579 }
580
581 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
582 _Blob blob = _decodeBlob(p, end, false);
583 p = blob.p;
584 end = blob.end;
585
586 std::vector<Member> members;
587 while (p < end) {
588 const Member member = _popMemberBlob(p, end);
589 if (member)
590 members.push_back(member);
591 else
592 break;
593 }
594 return members;
595 }
596
597 void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
598 const DataType& type = obj.type();
599 if (type.isPrimitive() && !type.isPointer()) {
600 obj.m_data.resize(type.size());
601 if (type.isInteger() || type.isEnum()) {
602 if (type.isSigned()) {
603 if (type.size() == 1)
604 _popIntBlob<int8_t>(p, end, obj.m_data);
605 else if (type.size() == 2)
606 _popIntBlob<int16_t>(p, end, obj.m_data);
607 else if (type.size() == 4)
608 _popIntBlob<int32_t>(p, end, obj.m_data);
609 else if (type.size() == 8)
610 _popIntBlob<int64_t>(p, end, obj.m_data);
611 else
612 assert(false /* unknown signed int type size */);
613 } else {
614 if (type.size() == 1)
615 _popIntBlob<uint8_t>(p, end, obj.m_data);
616 else if (type.size() == 2)
617 _popIntBlob<uint16_t>(p, end, obj.m_data);
618 else if (type.size() == 4)
619 _popIntBlob<uint32_t>(p, end, obj.m_data);
620 else if (type.size() == 8)
621 _popIntBlob<uint64_t>(p, end, obj.m_data);
622 else
623 assert(false /* unknown unsigned int type size */);
624 }
625 } else if (type.isReal()) {
626 if (type.size() == sizeof(float))
627 _popRealBlob<float>(p, end, obj.m_data);
628 else if (type.size() == sizeof(double))
629 _popRealBlob<double>(p, end, obj.m_data);
630 else
631 assert(false /* unknown floating point type */);
632 } else if (type.isBool()) {
633 _popIntBlob<uint8_t>(p, end, obj.m_data);
634 } else {
635 assert(false /* unknown primitive type */);
636 }
637
638 } else {
639 // don't whine if the empty blob was not added on encoder side
640 _Blob blob = _decodeBlob(p, end, false);
641 p = blob.p;
642 end = blob.end;
643 }
644 }
645
646 Object _popObjectBlob(const char*& p, const char* end) {
647 _Blob blob = _decodeBlob(p, end, false);
648 p = blob.p;
649 end = blob.end;
650
651 Object obj;
652 if (p >= end) return obj;
653
654 obj.m_type = _popDataTypeBlob(p, end);
655 obj.m_version = _popIntBlob<Version>(p, end);
656 obj.m_minVersion = _popIntBlob<Version>(p, end);
657 obj.m_uid = _popUIDChainBlob(p, end);
658 obj.m_members = _popMembersBlob(p, end);
659 _popPrimitiveValue(p, end, obj);
660 assert(obj.type());
661 return obj;
662 }
663
664 void Archive::_popObjectsBlob(const char*& p, const char* end) {
665 _Blob blob = _decodeBlob(p, end, false);
666 p = blob.p;
667 end = blob.end;
668
669 if (p >= end)
670 throw Exception("Decode Error: Premature end of objects blob");
671
672 while (true) {
673 const Object obj = _popObjectBlob(p, end);
674 if (!obj) break;
675 m_allObjects[obj.uid()] = obj;
676 }
677 }
678
679 void Archive::_popRootBlob(const char*& p, const char* end) {
680 _Blob blob = _decodeBlob(p, end, false);
681 p = blob.p;
682 end = blob.end;
683
684 if (p >= end)
685 throw Exception("Decode Error: Premature end of root blob");
686
687 // just in case this encoding format will be extended in future
688 // (currently not used)
689 const int formatMinorVersion = _popIntBlob<int>(p, end);
690
691 m_root = _popUIDBlob(p, end);
692 if (!m_root)
693 throw Exception("Decode Error: No root object");
694
695 _popObjectsBlob(p, end);
696 if (!m_allObjects[m_root])
697 throw Exception("Decode Error: Missing declared root object");
698 }
699
700 void Archive::decode(const RawData& data) {
701 m_rawData = data;
702 m_allObjects.clear();
703 const char* p = (const char*) &data[0];
704 const char* end = p + data.size();
705 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
706 throw Exception("Decode Error: Magic start missing!");
707 p += strlen(MAGIC_START);
708 _popRootBlob(p, end);
709 }
710
711 void Archive::decode(const uint8_t* data, size_t size) {
712 RawData rawData;
713 rawData.resize(size);
714 memcpy(&rawData[0], data, size);
715 decode(rawData);
716 }
717
718 String Archive::rawDataFormat() const {
719 return MAGIC_START;
720 }
721
722 void Archive::clear() {
723 m_allObjects.clear();
724 m_operation = OPERATION_NONE;
725 m_root = NO_UID;
726 m_rawData.clear();
727 }
728
729 void Archive::remove(const Object& obj) {
730 if (!obj.uid()) return;
731 m_allObjects.erase(obj.uid());
732 }
733
734 Object& Archive::objectByUID(const UID& uid) {
735 return m_allObjects[uid];
736 }
737
738 // *************** Archive::Syncer ***************
739 // *
740
741 Archive::Syncer::Syncer(Archive& dst, Archive& src)
742 : m_dst(dst), m_src(src)
743 {
744 const Object srcRootObj = src.rootObject();
745 const Object dstRootObj = dst.rootObject();
746 if (!srcRootObj)
747 throw Exception("No source root object!");
748 if (!dstRootObj)
749 throw Exception("Expected destination root object not found!");
750 syncObject(dstRootObj, srcRootObj);
751 }
752
753 void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
754 assert(srcObj.rawData().size() == dstObj.type().size());
755 void* pDst = (void*)dstObj.uid().id;
756 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
757 }
758
759 void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
760 assert(dstObj.type().isPointer());
761 assert(dstObj.type() == srcObj.type());
762 const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
763 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
764 syncObject(pointedDstObject, pointedSrcObject);
765 }
766
767 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
768 if (!dstObj || !srcObj) return; // end of recursion
769 if (!dstObj.isVersionCompatibleTo(srcObj))
770 throw Exception("Version incompatible (destination version " +
771 ToString(dstObj.version()) + " [min. version " +
772 ToString(dstObj.minVersion()) + "], source version " +
773 ToString(srcObj.version()) + " [min. version " +
774 ToString(srcObj.minVersion()) + "])");
775 if (dstObj.type() != srcObj.type())
776 throw Exception("Incompatible data structure type (destination type " +
777 dstObj.type().asLongDescr() + " vs. source type " +
778 srcObj.type().asLongDescr() + ")");
779
780 // prevent syncing this object again, and thus also prevent endless
781 // loop on data structures with cyclic relations
782 m_dst.m_allObjects.erase(dstObj.uid());
783
784 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
785 syncPrimitive(dstObj, srcObj);
786 return; // end of recursion
787 }
788
789 if (dstObj.type().isPointer()) {
790 syncPointer(dstObj, srcObj);
791 return;
792 }
793
794 assert(dstObj.type().isClass());
795 for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
796 const Member& srcMember = srcObj.members()[iMember];
797 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
798 if (!dstMember)
799 throw Exception("Expected member missing in destination object");
800 syncMember(dstMember, srcMember);
801 }
802 }
803
804 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
805 Member dstMember = dstObj.memberNamed(srcMember.name());
806 if (dstMember)
807 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
808 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
809 if (members.size() <= 0)
810 return Member();
811 if (members.size() == 1)
812 return members[0];
813 for (int i = 0; i < members.size(); ++i)
814 if (members[i].offset() == srcMember.offset())
815 return members[i];
816 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
817 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
818 for (int i = 0; i < members.size(); ++i) {
819 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
820 if (dstSeqNr == srcSeqNr)
821 return members[i];
822 }
823 return Member(); // give up!
824 }
825
826 void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
827 assert(dstMember && srcMember);
828 assert(dstMember.type() == srcMember.type());
829 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
830 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
831 syncObject(dstObj, srcObj);
832 }
833
834 // *************** Exception ***************
835 // *
836
837 void Exception::PrintMessage() {
838 std::cout << "Serialization::Exception: " << Message << std::endl;
839 }
840
841 } // namespace Serialization

  ViewVC Help
Powered by ViewVC