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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3169 - (hide annotations) (download)
Wed May 10 21:17:10 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 40353 byte(s)
* src/gig.h: Added enum reflection API functions for
  retrieving enum declaration type information at
  runtime (countEnum(), enumKey(), enumKeys(),
  enumValue()).
* Archive: Added methods valueAsInt(), valueAsReal()
  and valueAsBool().
* Bumped version (4.0.0.svn20).

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

  ViewVC Help
Powered by ViewVC