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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3139 - (show annotations) (download)
Wed May 3 15:15:10 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 27814 byte(s)
- Serialization.cpp: fixed misused atof_l().

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

  ViewVC Help
Powered by ViewVC