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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3182 - (show annotations) (download)
Sun May 14 20:40:02 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 41083 byte(s)
* Serialization framework: moved methods setVersion() and
  setMinVersion() from class Object to class Archive, and
  hide enum type operation_t from the public API.
* Bumped version (4.0.0.svn23).

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 #include <cxxabi.h>
31
32 #include "helper.h"
33
34 #define LIBGIG_EPOCH_TIME ((time_t)0)
35
36 namespace Serialization {
37
38 // *************** DataType ***************
39 // *
40
41 static UID _createNullUID() {
42 const UID uid = { NULL, 0 };
43 return uid;
44 }
45
46 const UID NO_UID = _createNullUID();
47
48 bool UID::isValid() const {
49 return id != NULL && id != (void*)-1 && size;
50 }
51
52 // *************** DataType ***************
53 // *
54
55 DataType::DataType() {
56 m_size = 0;
57 m_isPointer = false;
58 }
59
60 DataType::DataType(bool isPointer, int size, String baseType, String customType) {
61 m_size = size;
62 m_isPointer = isPointer;
63 m_baseTypeName = baseType;
64 m_customTypeName = customType;
65 }
66
67 bool DataType::isValid() const {
68 return m_size;
69 }
70
71 bool DataType::isPointer() const {
72 return m_isPointer;
73 }
74
75 bool DataType::isClass() const {
76 return m_baseTypeName == "class";
77 }
78
79 bool DataType::isPrimitive() const {
80 return !isClass();
81 }
82
83 bool DataType::isInteger() const {
84 return m_baseTypeName.substr(0, 3) == "int" ||
85 m_baseTypeName.substr(0, 4) == "uint";
86 }
87
88 bool DataType::isReal() const {
89 return m_baseTypeName.substr(0, 4) == "real";
90 }
91
92 bool DataType::isBool() const {
93 return m_baseTypeName == "bool";
94 }
95
96 bool DataType::isEnum() const {
97 return m_baseTypeName == "enum";
98 }
99
100 bool DataType::isSigned() const {
101 return m_baseTypeName.substr(0, 3) == "int" ||
102 isReal();
103 }
104
105 bool DataType::operator==(const DataType& other) const {
106 return m_baseTypeName == other.m_baseTypeName &&
107 m_customTypeName == other.m_customTypeName &&
108 m_size == other.m_size &&
109 m_isPointer == other.m_isPointer;
110 }
111
112 bool DataType::operator!=(const DataType& other) const {
113 return !operator==(other);
114 }
115
116 bool DataType::operator<(const DataType& other) const {
117 return m_baseTypeName < other.m_baseTypeName ||
118 (m_baseTypeName == other.m_baseTypeName &&
119 m_customTypeName < other.m_customTypeName ||
120 (m_customTypeName == other.m_customTypeName &&
121 m_size < other.m_size ||
122 (m_size == other.m_size &&
123 m_isPointer < other.m_isPointer)));
124 }
125
126 bool DataType::operator>(const DataType& other) const {
127 return !(operator==(other) || operator<(other));
128 }
129
130 String DataType::asLongDescr() const {
131 String s = m_baseTypeName;
132 if (!m_customTypeName.empty())
133 s += " " + customTypeName(true);
134 if (isPointer())
135 s += " pointer";
136 return s;
137 }
138
139 String DataType::customTypeName(bool demangle) const {
140 if (!demangle) return m_customTypeName;
141 int status;
142 const char* result =
143 abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
144 return (status == 0) ? result : m_customTypeName;
145 }
146
147 // *************** Member ***************
148 // *
149
150 Member::Member() {
151 m_uid = NO_UID;
152 m_offset = 0;
153 }
154
155 Member::Member(String name, UID uid, size_t offset, DataType type) {
156 m_name = name;
157 m_uid = uid;
158 m_offset = offset;
159 m_type = type;
160 }
161
162 bool Member::isValid() const {
163 return m_uid && !m_name.empty() && m_type;
164 }
165
166 bool Member::operator==(const Member& other) const {
167 return m_uid == other.m_uid &&
168 m_offset == other.m_offset &&
169 m_name == other.m_name &&
170 m_type == other.m_type;
171 }
172
173 bool Member::operator!=(const Member& other) const {
174 return !operator==(other);
175 }
176
177 bool Member::operator<(const Member& other) const {
178 return m_uid < other.m_uid ||
179 (m_uid == other.m_uid &&
180 m_offset < other.m_offset ||
181 (m_offset == other.m_offset &&
182 m_name < other.m_name ||
183 (m_name == other.m_name &&
184 m_type < other.m_type)));
185 }
186
187 bool Member::operator>(const Member& other) const {
188 return !(operator==(other) || operator<(other));
189 }
190
191 // *************** Object ***************
192 // *
193
194 Object::Object() {
195 m_version = 0;
196 m_minVersion = 0;
197 }
198
199 Object::Object(UIDChain uidChain, DataType type) {
200 m_type = type;
201 m_uid = uidChain;
202 m_version = 0;
203 m_minVersion = 0;
204 //m_data.resize(type.size());
205 }
206
207 bool Object::isValid() const {
208 return m_type && !m_uid.empty();
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_type == other.m_type;
216 }
217
218 bool Object::operator!=(const Object& other) const {
219 return !operator==(other);
220 }
221
222 bool Object::operator<(const Object& other) const {
223 // ignoring all other member variables here
224 // (since UID stands for "unique" ;-) )
225 return m_uid < other.m_uid ||
226 (m_uid == other.m_uid &&
227 m_type < other.m_type);
228 }
229
230 bool Object::operator>(const Object& other) const {
231 return !(operator==(other) || operator<(other));
232 }
233
234 bool Object::isVersionCompatibleTo(const Object& other) const {
235 if (this->version() == other.version())
236 return true;
237 if (this->version() > other.version())
238 return this->minVersion() <= other.version();
239 else
240 return other.minVersion() <= this->version();
241 }
242
243 void Object::setVersion(Version v) {
244 m_version = v;
245 }
246
247 void Object::setMinVersion(Version v) {
248 m_minVersion = v;
249 }
250
251 Member Object::memberNamed(String name) const {
252 for (int i = 0; i < m_members.size(); ++i)
253 if (m_members[i].name() == name)
254 return m_members[i];
255 return Member();
256 }
257
258 Member Object::memberByUID(const UID& uid) const {
259 if (!uid) return Member();
260 for (int i = 0; i < m_members.size(); ++i)
261 if (m_members[i].uid() == uid)
262 return m_members[i];
263 return Member();
264 }
265
266 void Object::remove(const Member& member) {
267 for (int i = 0; i < m_members.size(); ++i) {
268 if (m_members[i] == member) {
269 m_members.erase(m_members.begin() + i);
270 return;
271 }
272 }
273 }
274
275 std::vector<Member> Object::membersOfType(const DataType& type) const {
276 std::vector<Member> v;
277 for (int i = 0; i < m_members.size(); ++i) {
278 const Member& member = m_members[i];
279 if (member.type() == type)
280 v.push_back(member);
281 }
282 return v;
283 }
284
285 int Object::sequenceIndexOf(const Member& member) const {
286 for (int i = 0; i < m_members.size(); ++i)
287 if (m_members[i] == member)
288 return i;
289 return -1;
290 }
291
292 // *************** Archive ***************
293 // *
294
295 Archive::Archive() {
296 m_operation = OPERATION_NONE;
297 m_root = NO_UID;
298 m_isModified = false;
299 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
300 }
301
302 Archive::Archive(const RawData& data) {
303 m_operation = OPERATION_NONE;
304 m_root = NO_UID;
305 m_isModified = false;
306 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
307 decode(m_rawData);
308 }
309
310 Archive::Archive(const uint8_t* data, size_t size) {
311 m_operation = OPERATION_NONE;
312 m_root = NO_UID;
313 m_isModified = false;
314 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
315 decode(data, size);
316 }
317
318 Archive::~Archive() {
319 }
320
321 Object& Archive::rootObject() {
322 return m_allObjects[m_root];
323 }
324
325 static String _encodeBlob(String data) {
326 return ToString(data.length()) + ":" + data;
327 }
328
329 static String _encode(const UID& uid) {
330 String s;
331 s += _encodeBlob(ToString(size_t(uid.id)));
332 s += _encodeBlob(ToString(size_t(uid.size)));
333 return _encodeBlob(s);
334 }
335
336 static String _encode(const time_t& time) {
337 return _encodeBlob(ToString(time));
338 }
339
340 static String _encode(const DataType& type) {
341 String s;
342 s += _encodeBlob(type.baseTypeName());
343 s += _encodeBlob(type.customTypeName());
344 s += _encodeBlob(ToString(type.size()));
345 s += _encodeBlob(ToString(type.isPointer()));
346 return _encodeBlob(s);
347 }
348
349 static String _encode(const UIDChain& chain) {
350 String s;
351 for (int i = 0; i < chain.size(); ++i)
352 s += _encode(chain[i]);
353 return _encodeBlob(s);
354 }
355
356 static String _encode(const Member& member) {
357 String s;
358 s += _encode(member.uid());
359 s += _encodeBlob(ToString(member.offset()));
360 s += _encodeBlob(member.name());
361 s += _encode(member.type());
362 return _encodeBlob(s);
363 }
364
365 static String _encode(const std::vector<Member>& members) {
366 String s;
367 for (int i = 0; i < members.size(); ++i)
368 s += _encode(members[i]);
369 return _encodeBlob(s);
370 }
371
372 static String _primitiveObjectValueToString(const Object& obj) {
373 String s;
374 const DataType& type = obj.type();
375 const ID& id = obj.uid().id;
376 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
377 if (!obj.m_data.empty())
378 assert(type.size() == obj.m_data.size());
379 if (type.isPrimitive() && !type.isPointer()) {
380 if (type.isInteger() || type.isEnum()) {
381 if (type.isSigned()) {
382 if (type.size() == 1)
383 s = ToString((int16_t)*(int8_t*)ptr); // int16_t: prevent ToString() to render an ASCII character
384 else if (type.size() == 2)
385 s = ToString(*(int16_t*)ptr);
386 else if (type.size() == 4)
387 s = ToString(*(int32_t*)ptr);
388 else if (type.size() == 8)
389 s = ToString(*(int64_t*)ptr);
390 else
391 assert(false /* unknown signed int type size */);
392 } else {
393 if (type.size() == 1)
394 s = ToString((uint16_t)*(uint8_t*)ptr); // uint16_t: prevent ToString() to render an ASCII character
395 else if (type.size() == 2)
396 s = ToString(*(uint16_t*)ptr);
397 else if (type.size() == 4)
398 s = ToString(*(uint32_t*)ptr);
399 else if (type.size() == 8)
400 s = ToString(*(uint64_t*)ptr);
401 else
402 assert(false /* unknown unsigned int type size */);
403 }
404 } else if (type.isReal()) {
405 if (type.size() == sizeof(float))
406 s = ToString(*(float*)ptr);
407 else if (type.size() == sizeof(double))
408 s = ToString(*(double*)ptr);
409 else
410 assert(false /* unknown floating point type */);
411 } else if (type.isBool()) {
412 s = ToString(*(bool*)ptr);
413 } else {
414 assert(false /* unknown primitive type */);
415 }
416
417 }
418 return s;
419 }
420
421 template<typename T>
422 static T _primitiveObjectValueToNumber(const Object& obj) {
423 T value = 0;
424 const DataType& type = obj.type();
425 const ID& id = obj.uid().id;
426 void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
427 if (!obj.m_data.empty())
428 assert(type.size() == obj.m_data.size());
429 if (type.isPrimitive() && !type.isPointer()) {
430 if (type.isInteger() || type.isEnum()) {
431 if (type.isSigned()) {
432 if (type.size() == 1)
433 value = (T)*(int8_t*)ptr;
434 else if (type.size() == 2)
435 value = (T)*(int16_t*)ptr;
436 else if (type.size() == 4)
437 value = (T)*(int32_t*)ptr;
438 else if (type.size() == 8)
439 value = (T)*(int64_t*)ptr;
440 else
441 assert(false /* unknown signed int type size */);
442 } else {
443 if (type.size() == 1)
444 value = (T)*(uint8_t*)ptr;
445 else if (type.size() == 2)
446 value = (T)*(uint16_t*)ptr;
447 else if (type.size() == 4)
448 value = (T)*(uint32_t*)ptr;
449 else if (type.size() == 8)
450 value = (T)*(uint64_t*)ptr;
451 else
452 assert(false /* unknown unsigned int type size */);
453 }
454 } else if (type.isReal()) {
455 if (type.size() == sizeof(float))
456 value = (T)*(float*)ptr;
457 else if (type.size() == sizeof(double))
458 value = (T)*(double*)ptr;
459 else
460 assert(false /* unknown floating point type */);
461 } else if (type.isBool()) {
462 value = (T)*(bool*)ptr;
463 } else {
464 assert(false /* unknown primitive type */);
465 }
466 }
467 return value;
468 }
469
470 static String _encodePrimitiveValue(const Object& obj) {
471 return _encodeBlob( _primitiveObjectValueToString(obj) );
472 }
473
474 static String _encode(const Object& obj) {
475 String s;
476 s += _encode(obj.type());
477 s += _encodeBlob(ToString(obj.version()));
478 s += _encodeBlob(ToString(obj.minVersion()));
479 s += _encode(obj.uidChain());
480 s += _encode(obj.members());
481 s += _encodePrimitiveValue(obj);
482 return _encodeBlob(s);
483 }
484
485 String _encode(const Archive::ObjectPool& objects) {
486 String s;
487 for (Archive::ObjectPool::const_iterator itObject = objects.begin();
488 itObject != objects.end(); ++itObject)
489 {
490 const Object& obj = itObject->second;
491 s += _encode(obj);
492 }
493 return _encodeBlob(s);
494 }
495
496 #define MAGIC_START "Srx1v"
497 #define ENCODING_FORMAT_MINOR_VERSION 0
498
499 String Archive::_encodeRootBlob() {
500 String s;
501 s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
502 s += _encode(m_root);
503 s += _encode(m_allObjects);
504 s += _encodeBlob(m_name);
505 s += _encodeBlob(m_comment);
506 s += _encode(m_timeCreated);
507 s += _encode(m_timeModified);
508 return _encodeBlob(s);
509 }
510
511 void Archive::encode() {
512 m_rawData.clear();
513 String s = MAGIC_START;
514 m_timeModified = time(NULL);
515 if (m_timeCreated == LIBGIG_EPOCH_TIME)
516 m_timeCreated = m_timeModified;
517 s += _encodeRootBlob();
518 m_rawData.resize(s.length() + 1);
519 memcpy(&m_rawData[0], &s[0], s.length() + 1);
520 m_isModified = false;
521 }
522
523 struct _Blob {
524 const char* p;
525 const char* end;
526 };
527
528 static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
529 if (!bThrow && p >= end) {
530 const _Blob blob = { p, end };
531 return blob;
532 }
533 size_t sz = 0;
534 for (; true; ++p) {
535 if (p >= end)
536 throw Exception("Decode Error: Missing blob");
537 const char& c = *p;
538 if (c == ':') break;
539 if (c < '0' || c > '9')
540 throw Exception("Decode Error: Missing blob size");
541 sz *= 10;
542 sz += size_t(c - '0');
543 }
544 ++p;
545 if (p + sz > end)
546 throw Exception("Decode Error: Premature end of blob");
547 const _Blob blob = { p, p + sz };
548 return blob;
549 }
550
551 template<typename T_int>
552 static T_int _popIntBlob(const char*& p, const char* end) {
553 _Blob blob = _decodeBlob(p, end);
554 p = blob.p;
555 end = blob.end;
556
557 T_int sign = 1;
558 T_int i = 0;
559 if (p >= end)
560 throw Exception("Decode Error: premature end of int blob");
561 if (*p == '-') {
562 sign = -1;
563 ++p;
564 }
565 for (; p < end; ++p) {
566 const char& c = *p;
567 if (c < '0' || c > '9')
568 throw Exception("Decode Error: Invalid int blob format");
569 i *= 10;
570 i += size_t(c - '0');
571 }
572 return i * sign;
573 }
574
575 template<typename T_int>
576 static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
577 const T_int i = _popIntBlob<T_int>(p, end);
578 *(T_int*)&rawData[0] = i;
579 }
580
581 template<typename T_real>
582 static T_real _popRealBlob(const char*& p, const char* end) {
583 _Blob blob = _decodeBlob(p, end);
584 p = blob.p;
585 end = blob.end;
586
587 if (p >= end || (end - p) < 1)
588 throw Exception("Decode Error: premature end of real blob");
589
590 String s(p, size_t(end - p));
591
592 T_real r;
593 if (sizeof(T_real) <= sizeof(double))
594 r = atof(s.c_str());
595 else
596 assert(false /* unknown real type */);
597
598 p += s.length();
599
600 return r;
601 }
602
603 template<typename T_real>
604 static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
605 const T_real r = _popRealBlob<T_real>(p, end);
606 *(T_real*)&rawData[0] = r;
607 }
608
609 static String _popStringBlob(const char*& p, const char* end) {
610 _Blob blob = _decodeBlob(p, end);
611 p = blob.p;
612 end = blob.end;
613 if (end - p < 0)
614 throw Exception("Decode Error: missing String blob");
615 String s;
616 const size_t sz = end - p;
617 s.resize(sz);
618 memcpy(&s[0], p, sz);
619 p += sz;
620 return s;
621 }
622
623 static time_t _popTimeBlob(const char*& p, const char* end) {
624 const uint64_t i = _popIntBlob<uint64_t>(p, end);
625 return (time_t) i;
626 }
627
628 DataType _popDataTypeBlob(const char*& p, const char* end) {
629 _Blob blob = _decodeBlob(p, end);
630 p = blob.p;
631 end = blob.end;
632
633 DataType type;
634 type.m_baseTypeName = _popStringBlob(p, end);
635 type.m_customTypeName = _popStringBlob(p, end);
636 type.m_size = _popIntBlob<int>(p, end);
637 type.m_isPointer = _popIntBlob<bool>(p, end);
638 return type;
639 }
640
641 static UID _popUIDBlob(const char*& p, const char* end) {
642 _Blob blob = _decodeBlob(p, end);
643 p = blob.p;
644 end = blob.end;
645
646 if (p >= end)
647 throw Exception("Decode Error: premature end of UID blob");
648
649 const ID id = (ID) _popIntBlob<size_t>(p, end);
650 const size_t size = _popIntBlob<size_t>(p, end);
651
652 const UID uid = { id, size };
653 return uid;
654 }
655
656 static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
657 _Blob blob = _decodeBlob(p, end);
658 p = blob.p;
659 end = blob.end;
660
661 UIDChain chain;
662 while (p < end) {
663 const UID uid = _popUIDBlob(p, end);
664 chain.push_back(uid);
665 }
666 assert(!chain.empty());
667 return chain;
668 }
669
670 static Member _popMemberBlob(const char*& p, const char* end) {
671 _Blob blob = _decodeBlob(p, end, false);
672 p = blob.p;
673 end = blob.end;
674
675 Member m;
676 if (p >= end) return m;
677
678 m.m_uid = _popUIDBlob(p, end);
679 m.m_offset = _popIntBlob<size_t>(p, end);
680 m.m_name = _popStringBlob(p, end);
681 m.m_type = _popDataTypeBlob(p, end);
682 assert(m.type());
683 assert(!m.name().empty());
684 assert(m.uid().isValid());
685 return m;
686 }
687
688 static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
689 _Blob blob = _decodeBlob(p, end, false);
690 p = blob.p;
691 end = blob.end;
692
693 std::vector<Member> members;
694 while (p < end) {
695 const Member member = _popMemberBlob(p, end);
696 if (member)
697 members.push_back(member);
698 else
699 break;
700 }
701 return members;
702 }
703
704 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
705 const DataType& type = obj.type();
706 if (type.isPrimitive() && !type.isPointer()) {
707 obj.m_data.resize(type.size());
708 if (type.isInteger() || type.isEnum()) {
709 if (type.isSigned()) {
710 if (type.size() == 1)
711 _popIntBlob<int8_t>(p, end, obj.m_data);
712 else if (type.size() == 2)
713 _popIntBlob<int16_t>(p, end, obj.m_data);
714 else if (type.size() == 4)
715 _popIntBlob<int32_t>(p, end, obj.m_data);
716 else if (type.size() == 8)
717 _popIntBlob<int64_t>(p, end, obj.m_data);
718 else
719 assert(false /* unknown signed int type size */);
720 } else {
721 if (type.size() == 1)
722 _popIntBlob<uint8_t>(p, end, obj.m_data);
723 else if (type.size() == 2)
724 _popIntBlob<uint16_t>(p, end, obj.m_data);
725 else if (type.size() == 4)
726 _popIntBlob<uint32_t>(p, end, obj.m_data);
727 else if (type.size() == 8)
728 _popIntBlob<uint64_t>(p, end, obj.m_data);
729 else
730 assert(false /* unknown unsigned int type size */);
731 }
732 } else if (type.isReal()) {
733 if (type.size() == sizeof(float))
734 _popRealBlob<float>(p, end, obj.m_data);
735 else if (type.size() == sizeof(double))
736 _popRealBlob<double>(p, end, obj.m_data);
737 else
738 assert(false /* unknown floating point type */);
739 } else if (type.isBool()) {
740 _popIntBlob<uint8_t>(p, end, obj.m_data);
741 } else {
742 assert(false /* unknown primitive type */);
743 }
744
745 } else {
746 // don't whine if the empty blob was not added on encoder side
747 _Blob blob = _decodeBlob(p, end, false);
748 p = blob.p;
749 end = blob.end;
750 }
751 }
752
753 static Object _popObjectBlob(const char*& p, const char* end) {
754 _Blob blob = _decodeBlob(p, end, false);
755 p = blob.p;
756 end = blob.end;
757
758 Object obj;
759 if (p >= end) return obj;
760
761 obj.m_type = _popDataTypeBlob(p, end);
762 obj.m_version = _popIntBlob<Version>(p, end);
763 obj.m_minVersion = _popIntBlob<Version>(p, end);
764 obj.m_uid = _popUIDChainBlob(p, end);
765 obj.m_members = _popMembersBlob(p, end);
766 _popPrimitiveValue(p, end, obj);
767 assert(obj.type());
768 return obj;
769 }
770
771 void Archive::_popObjectsBlob(const char*& p, const char* end) {
772 _Blob blob = _decodeBlob(p, end, false);
773 p = blob.p;
774 end = blob.end;
775
776 if (p >= end)
777 throw Exception("Decode Error: Premature end of objects blob");
778
779 while (true) {
780 const Object obj = _popObjectBlob(p, end);
781 if (!obj) break;
782 m_allObjects[obj.uid()] = obj;
783 }
784 }
785
786 void Archive::_popRootBlob(const char*& p, const char* end) {
787 _Blob blob = _decodeBlob(p, end, false);
788 p = blob.p;
789 end = blob.end;
790
791 if (p >= end)
792 throw Exception("Decode Error: Premature end of root blob");
793
794 // just in case this encoding format will be extended in future
795 // (currently not used)
796 const int formatMinorVersion = _popIntBlob<int>(p, end);
797
798 m_root = _popUIDBlob(p, end);
799 if (!m_root)
800 throw Exception("Decode Error: No root object");
801
802 _popObjectsBlob(p, end);
803 if (!m_allObjects[m_root])
804 throw Exception("Decode Error: Missing declared root object");
805
806 m_name = _popStringBlob(p, end);
807 m_comment = _popStringBlob(p, end);
808 m_timeCreated = _popTimeBlob(p, end);
809 m_timeModified = _popTimeBlob(p, end);
810 }
811
812 void Archive::decode(const RawData& data) {
813 m_rawData = data;
814 m_allObjects.clear();
815 m_isModified = false;
816 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
817 const char* p = (const char*) &data[0];
818 const char* end = p + data.size();
819 if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
820 throw Exception("Decode Error: Magic start missing!");
821 p += strlen(MAGIC_START);
822 _popRootBlob(p, end);
823 }
824
825 void Archive::decode(const uint8_t* data, size_t size) {
826 RawData rawData;
827 rawData.resize(size);
828 memcpy(&rawData[0], data, size);
829 decode(rawData);
830 }
831
832 const RawData& Archive::rawData() {
833 if (m_isModified) encode();
834 return m_rawData;
835 }
836
837 String Archive::rawDataFormat() const {
838 return MAGIC_START;
839 }
840
841 bool Archive::isModified() const {
842 return m_isModified;
843 }
844
845 void Archive::clear() {
846 m_allObjects.clear();
847 m_operation = OPERATION_NONE;
848 m_root = NO_UID;
849 m_rawData.clear();
850 m_isModified = false;
851 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
852 }
853
854 String Archive::name() const {
855 return m_name;
856 }
857
858 void Archive::setName(String name) {
859 if (m_name == name) return;
860 m_name = name;
861 m_isModified = true;
862 }
863
864 String Archive::comment() const {
865 return m_comment;
866 }
867
868 void Archive::setComment(String comment) {
869 if (m_comment == comment) return;
870 m_comment = comment;
871 m_isModified = true;
872 }
873
874 static tm _convertTimeStamp(const time_t& time, time_base_t base) {
875 tm* pTm;
876 switch (base) {
877 case LOCAL_TIME:
878 pTm = localtime(&time);
879 break;
880 case UTC_TIME:
881 pTm = gmtime(&time);
882 break;
883 default:
884 throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
885 }
886 if (!pTm)
887 throw Exception("Failed assembling time stamp structure");
888 return *pTm;
889 }
890
891 time_t Archive::timeStampCreated() const {
892 return m_timeCreated;
893 }
894
895 time_t Archive::timeStampModified() const {
896 return m_timeModified;
897 }
898
899 tm Archive::dateTimeCreated(time_base_t base) const {
900 return _convertTimeStamp(m_timeCreated, base);
901 }
902
903 tm Archive::dateTimeModified(time_base_t base) const {
904 return _convertTimeStamp(m_timeModified, base);
905 }
906
907 void Archive::removeMember(Object& parent, const Member& member) {
908 parent.remove(member);
909 m_isModified = true;
910 }
911
912 void Archive::remove(const Object& obj) {
913 //FIXME: Should traverse from root object and remove all members associated with this object
914 if (!obj.uid()) return;
915 m_allObjects.erase(obj.uid());
916 m_isModified = true;
917 }
918
919 Object& Archive::objectByUID(const UID& uid) {
920 return m_allObjects[uid];
921 }
922
923 void Archive::setVersion(Object& object, Version v) {
924 if (!object) return;
925 object.setVersion(v);
926 m_isModified = true;
927 }
928
929 void Archive::setMinVersion(Object& object, Version v) {
930 if (!object) return;
931 object.setMinVersion(v);
932 m_isModified = true;
933 }
934
935 void Archive::setEnumValue(Object& object, uint64_t value) {
936 if (!object) return;
937 if (!object.type().isEnum())
938 throw Exception("Not an enum data type");
939 Object* pObject = &object;
940 if (object.type().isPointer()) {
941 Object& obj = objectByUID(object.uid(1));
942 if (!obj) return;
943 pObject = &obj;
944 }
945 const int nativeEnumSize = sizeof(enum operation_t);
946 DataType& type = const_cast<DataType&>( pObject->type() );
947 // original serializer ("sender") might have had a different word size
948 // than this machine, adjust type object in this case
949 if (type.size() != nativeEnumSize) {
950 type.m_size = nativeEnumSize;
951 }
952 pObject->m_data.resize(type.size());
953 void* ptr = &pObject->m_data[0];
954 if (type.size() == 1)
955 *(uint8_t*)ptr = (uint8_t)value;
956 else if (type.size() == 2)
957 *(uint16_t*)ptr = (uint16_t)value;
958 else if (type.size() == 4)
959 *(uint32_t*)ptr = (uint32_t)value;
960 else if (type.size() == 8)
961 *(uint64_t*)ptr = (uint64_t)value;
962 else
963 assert(false /* unknown enum type size */);
964 m_isModified = true;
965 }
966
967 void Archive::setIntValue(Object& object, int64_t value) {
968 if (!object) return;
969 if (!object.type().isInteger())
970 throw Exception("Not an integer data type");
971 Object* pObject = &object;
972 if (object.type().isPointer()) {
973 Object& obj = objectByUID(object.uid(1));
974 if (!obj) return;
975 pObject = &obj;
976 }
977 const DataType& type = pObject->type();
978 pObject->m_data.resize(type.size());
979 void* ptr = &pObject->m_data[0];
980 if (type.isSigned()) {
981 if (type.size() == 1)
982 *(int8_t*)ptr = (int8_t)value;
983 else if (type.size() == 2)
984 *(int16_t*)ptr = (int16_t)value;
985 else if (type.size() == 4)
986 *(int32_t*)ptr = (int32_t)value;
987 else if (type.size() == 8)
988 *(int64_t*)ptr = (int64_t)value;
989 else
990 assert(false /* unknown signed int type size */);
991 } else {
992 if (type.size() == 1)
993 *(uint8_t*)ptr = (uint8_t)value;
994 else if (type.size() == 2)
995 *(uint16_t*)ptr = (uint16_t)value;
996 else if (type.size() == 4)
997 *(uint32_t*)ptr = (uint32_t)value;
998 else if (type.size() == 8)
999 *(uint64_t*)ptr = (uint64_t)value;
1000 else
1001 assert(false /* unknown unsigned int type size */);
1002 }
1003 m_isModified = true;
1004 }
1005
1006 void Archive::setRealValue(Object& object, double value) {
1007 if (!object) return;
1008 if (!object.type().isReal())
1009 throw Exception("Not a real data type");
1010 Object* pObject = &object;
1011 if (object.type().isPointer()) {
1012 Object& obj = objectByUID(object.uid(1));
1013 if (!obj) return;
1014 pObject = &obj;
1015 }
1016 const DataType& type = pObject->type();
1017 pObject->m_data.resize(type.size());
1018 void* ptr = &pObject->m_data[0];
1019 if (type.size() == sizeof(float))
1020 *(float*)ptr = (float)value;
1021 else if (type.size() == sizeof(double))
1022 *(double*)ptr = (double)value;
1023 else
1024 assert(false /* unknown real type size */);
1025 m_isModified = true;
1026 }
1027
1028 void Archive::setBoolValue(Object& object, bool value) {
1029 if (!object) return;
1030 if (!object.type().isBool())
1031 throw Exception("Not a bool data type");
1032 Object* pObject = &object;
1033 if (object.type().isPointer()) {
1034 Object& obj = objectByUID(object.uid(1));
1035 if (!obj) return;
1036 pObject = &obj;
1037 }
1038 const DataType& type = pObject->type();
1039 pObject->m_data.resize(type.size());
1040 bool* ptr = (bool*)&pObject->m_data[0];
1041 *ptr = value;
1042 m_isModified = true;
1043 }
1044
1045 void Archive::setAutoValue(Object& object, String value) {
1046 if (!object) return;
1047 const DataType& type = object.type();
1048 if (type.isInteger())
1049 setIntValue(object, atoll(value.c_str()));
1050 else if (type.isReal())
1051 setRealValue(object, atof(value.c_str()));
1052 else if (type.isBool())
1053 setBoolValue(object, atof(value.c_str()));
1054 else if (type.isEnum())
1055 setEnumValue(object, atoll(value.c_str()));
1056 else
1057 throw Exception("Not a primitive data type");
1058 }
1059
1060 String Archive::valueAsString(const Object& object) {
1061 if (!object)
1062 throw Exception("Invalid object");
1063 if (object.type().isClass())
1064 throw Exception("Object is class type");
1065 const Object* pObject = &object;
1066 if (object.type().isPointer()) {
1067 const Object& obj = objectByUID(object.uid(1));
1068 if (!obj) return "";
1069 pObject = &obj;
1070 }
1071 return _primitiveObjectValueToString(*pObject);
1072 }
1073
1074 int64_t Archive::valueAsInt(const Object& object) {
1075 if (!object)
1076 throw Exception("Invalid object");
1077 if (!object.type().isInteger() && !object.type().isEnum())
1078 throw Exception("Object is neither an integer nor an enum");
1079 const Object* pObject = &object;
1080 if (object.type().isPointer()) {
1081 const Object& obj = objectByUID(object.uid(1));
1082 if (!obj) return 0;
1083 pObject = &obj;
1084 }
1085 return _primitiveObjectValueToNumber<int64_t>(*pObject);
1086 }
1087
1088 double Archive::valueAsReal(const Object& object) {
1089 if (!object)
1090 throw Exception("Invalid object");
1091 if (!object.type().isReal())
1092 throw Exception("Object is not an real type");
1093 const Object* pObject = &object;
1094 if (object.type().isPointer()) {
1095 const Object& obj = objectByUID(object.uid(1));
1096 if (!obj) return 0;
1097 pObject = &obj;
1098 }
1099 return _primitiveObjectValueToNumber<double>(*pObject);
1100 }
1101
1102 bool Archive::valueAsBool(const Object& object) {
1103 if (!object)
1104 throw Exception("Invalid object");
1105 if (!object.type().isBool())
1106 throw Exception("Object is not a bool");
1107 const Object* pObject = &object;
1108 if (object.type().isPointer()) {
1109 const Object& obj = objectByUID(object.uid(1));
1110 if (!obj) return 0;
1111 pObject = &obj;
1112 }
1113 return _primitiveObjectValueToNumber<bool>(*pObject);
1114 }
1115
1116 // *************** Archive::Syncer ***************
1117 // *
1118
1119 Archive::Syncer::Syncer(Archive& dst, Archive& src)
1120 : m_dst(dst), m_src(src)
1121 {
1122 const Object srcRootObj = src.rootObject();
1123 const Object dstRootObj = dst.rootObject();
1124 if (!srcRootObj)
1125 throw Exception("No source root object!");
1126 if (!dstRootObj)
1127 throw Exception("Expected destination root object not found!");
1128 syncObject(dstRootObj, srcRootObj);
1129 }
1130
1131 void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
1132 assert(srcObj.rawData().size() == dstObj.type().size());
1133 void* pDst = (void*)dstObj.uid().id;
1134 memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
1135 }
1136
1137 void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
1138 assert(dstObj.type().isPointer());
1139 assert(dstObj.type() == srcObj.type());
1140 const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
1141 const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
1142 syncObject(pointedDstObject, pointedSrcObject);
1143 }
1144
1145 void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
1146 if (!dstObj || !srcObj) return; // end of recursion
1147 if (!dstObj.isVersionCompatibleTo(srcObj))
1148 throw Exception("Version incompatible (destination version " +
1149 ToString(dstObj.version()) + " [min. version " +
1150 ToString(dstObj.minVersion()) + "], source version " +
1151 ToString(srcObj.version()) + " [min. version " +
1152 ToString(srcObj.minVersion()) + "])");
1153 if (dstObj.type() != srcObj.type())
1154 throw Exception("Incompatible data structure type (destination type " +
1155 dstObj.type().asLongDescr() + " vs. source type " +
1156 srcObj.type().asLongDescr() + ")");
1157
1158 // prevent syncing this object again, and thus also prevent endless
1159 // loop on data structures with cyclic relations
1160 m_dst.m_allObjects.erase(dstObj.uid());
1161
1162 if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
1163 syncPrimitive(dstObj, srcObj);
1164 return; // end of recursion
1165 }
1166
1167 if (dstObj.type().isPointer()) {
1168 syncPointer(dstObj, srcObj);
1169 return;
1170 }
1171
1172 assert(dstObj.type().isClass());
1173 for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
1174 const Member& srcMember = srcObj.members()[iMember];
1175 Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
1176 if (!dstMember)
1177 throw Exception("Expected member missing in destination object");
1178 syncMember(dstMember, srcMember);
1179 }
1180 }
1181
1182 Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
1183 Member dstMember = dstObj.memberNamed(srcMember.name());
1184 if (dstMember)
1185 return (dstMember.type() == srcMember.type()) ? dstMember : Member();
1186 std::vector<Member> members = dstObj.membersOfType(srcMember.type());
1187 if (members.size() <= 0)
1188 return Member();
1189 if (members.size() == 1)
1190 return members[0];
1191 for (int i = 0; i < members.size(); ++i)
1192 if (members[i].offset() == srcMember.offset())
1193 return members[i];
1194 const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
1195 assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
1196 for (int i = 0; i < members.size(); ++i) {
1197 const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
1198 if (dstSeqNr == srcSeqNr)
1199 return members[i];
1200 }
1201 return Member(); // give up!
1202 }
1203
1204 void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
1205 assert(dstMember && srcMember);
1206 assert(dstMember.type() == srcMember.type());
1207 const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
1208 const Object srcObj = m_src.m_allObjects[srcMember.uid()];
1209 syncObject(dstObj, srcObj);
1210 }
1211
1212 // *************** Exception ***************
1213 // *
1214
1215 void Exception::PrintMessage() {
1216 std::cout << "Serialization::Exception: " << Message << std::endl;
1217 }
1218
1219 } // namespace Serialization

  ViewVC Help
Powered by ViewVC