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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3173 - (hide annotations) (download)
Wed May 10 23:07:28 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 40623 byte(s)
* Print compiler warning if no RTTI available.
* Serialization::DataType class: Implemented demangling C++ type
  names (for methods asLongDescr() and
  customTypeName(bool demangle=false)).
* gig.h: When there is no RTTI, only hide API functions which
  really require RTTI.
* Bumped version (4.0.0.svn21).

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

  ViewVC Help
Powered by ViewVC