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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3159 - (show annotations) (download)
Mon May 8 21:15:16 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 36636 byte(s)
* Fix: Archive creation and modification time were
  not encoded correctly.
* Bumped version (4.0.0.svn19).

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

  ViewVC Help
Powered by ViewVC