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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3168 - (hide annotations) (download)
Tue May 9 19:12:32 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 36749 byte(s)
- More ancient compiler backward compatibility fixes.

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 3150 static String _encodePrimitiveValue(const Object& obj) {
406     return _encodeBlob( _primitiveObjectValueToString(obj) );
407     }
408    
409 schoenebeck 3138 static String _encode(const Object& obj) {
410     String s;
411     s += _encode(obj.type());
412     s += _encodeBlob(ToString(obj.version()));
413     s += _encodeBlob(ToString(obj.minVersion()));
414     s += _encode(obj.uidChain());
415     s += _encode(obj.members());
416     s += _encodePrimitiveValue(obj);
417     return _encodeBlob(s);
418     }
419    
420     String _encode(const Archive::ObjectPool& objects) {
421     String s;
422     for (Archive::ObjectPool::const_iterator itObject = objects.begin();
423     itObject != objects.end(); ++itObject)
424     {
425     const Object& obj = itObject->second;
426     s += _encode(obj);
427     }
428     return _encodeBlob(s);
429     }
430    
431     #define MAGIC_START "Srx1v"
432     #define ENCODING_FORMAT_MINOR_VERSION 0
433    
434     String Archive::_encodeRootBlob() {
435     String s;
436     s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
437     s += _encode(m_root);
438     s += _encode(m_allObjects);
439 schoenebeck 3156 s += _encodeBlob(m_name);
440     s += _encodeBlob(m_comment);
441     s += _encode(m_timeCreated);
442     s += _encode(m_timeModified);
443 schoenebeck 3138 return _encodeBlob(s);
444     }
445    
446     void Archive::encode() {
447     m_rawData.clear();
448     String s = MAGIC_START;
449 schoenebeck 3159 m_timeModified = time(NULL);
450     if (m_timeCreated == LIBGIG_EPOCH_TIME)
451     m_timeCreated = m_timeModified;
452 schoenebeck 3138 s += _encodeRootBlob();
453     m_rawData.resize(s.length() + 1);
454     memcpy(&m_rawData[0], &s[0], s.length() + 1);
455 schoenebeck 3150 m_isModified = false;
456 schoenebeck 3138 }
457    
458     struct _Blob {
459     const char* p;
460     const char* end;
461     };
462    
463     static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
464 schoenebeck 3168 if (!bThrow && p >= end) {
465     const _Blob blob = { p, end };
466     return blob;
467     }
468 schoenebeck 3138 size_t sz = 0;
469     for (; true; ++p) {
470     if (p >= end)
471     throw Exception("Decode Error: Missing blob");
472     const char& c = *p;
473     if (c == ':') break;
474     if (c < '0' || c > '9')
475     throw Exception("Decode Error: Missing blob size");
476     sz *= 10;
477     sz += size_t(c - '0');
478     }
479     ++p;
480     if (p + sz > end)
481     throw Exception("Decode Error: Premature end of blob");
482 schoenebeck 3168 const _Blob blob = { p, p + sz };
483     return blob;
484 schoenebeck 3138 }
485    
486     template<typename T_int>
487     static T_int _popIntBlob(const char*& p, const char* end) {
488     _Blob blob = _decodeBlob(p, end);
489     p = blob.p;
490     end = blob.end;
491    
492     T_int sign = 1;
493     T_int i = 0;
494     if (p >= end)
495     throw Exception("Decode Error: premature end of int blob");
496     if (*p == '-') {
497     sign = -1;
498     ++p;
499     }
500     for (; p < end; ++p) {
501     const char& c = *p;
502     if (c < '0' || c > '9')
503     throw Exception("Decode Error: Invalid int blob format");
504     i *= 10;
505     i += size_t(c - '0');
506     }
507     return i * sign;
508     }
509    
510     template<typename T_int>
511     static void _popIntBlob(const char*& p, const char* end, RawData& rawData) {
512     const T_int i = _popIntBlob<T_int>(p, end);
513     *(T_int*)&rawData[0] = i;
514     }
515    
516     template<typename T_real>
517     static T_real _popRealBlob(const char*& p, const char* end) {
518     _Blob blob = _decodeBlob(p, end);
519     p = blob.p;
520     end = blob.end;
521    
522     if (p >= end || (end - p) < 1)
523     throw Exception("Decode Error: premature end of real blob");
524    
525     String s(p, size_t(end - p));
526    
527     T_real r;
528 schoenebeck 3139 if (sizeof(T_real) <= sizeof(double))
529 schoenebeck 3138 r = atof(s.c_str());
530     else
531     assert(false /* unknown real type */);
532    
533     p += s.length();
534    
535     return r;
536     }
537    
538     template<typename T_real>
539     static void _popRealBlob(const char*& p, const char* end, RawData& rawData) {
540     const T_real r = _popRealBlob<T_real>(p, end);
541     *(T_real*)&rawData[0] = r;
542     }
543    
544     static String _popStringBlob(const char*& p, const char* end) {
545     _Blob blob = _decodeBlob(p, end);
546     p = blob.p;
547     end = blob.end;
548     if (end - p < 0)
549     throw Exception("Decode Error: missing String blob");
550     String s;
551     const size_t sz = end - p;
552     s.resize(sz);
553     memcpy(&s[0], p, sz);
554     p += sz;
555     return s;
556     }
557    
558 schoenebeck 3156 static time_t _popTimeBlob(const char*& p, const char* end) {
559     const uint64_t i = _popIntBlob<uint64_t>(p, end);
560     return (time_t) i;
561     }
562    
563 schoenebeck 3138 DataType _popDataTypeBlob(const char*& p, const char* end) {
564     _Blob blob = _decodeBlob(p, end);
565     p = blob.p;
566     end = blob.end;
567    
568     DataType type;
569     type.m_baseTypeName = _popStringBlob(p, end);
570     type.m_customTypeName = _popStringBlob(p, end);
571     type.m_size = _popIntBlob<int>(p, end);
572     type.m_isPointer = _popIntBlob<bool>(p, end);
573     return type;
574     }
575    
576     static UID _popUIDBlob(const char*& p, const char* end) {
577     _Blob blob = _decodeBlob(p, end);
578     p = blob.p;
579     end = blob.end;
580    
581     if (p >= end)
582     throw Exception("Decode Error: premature end of UID blob");
583    
584     const ID id = (ID) _popIntBlob<size_t>(p, end);
585     const size_t size = _popIntBlob<size_t>(p, end);
586    
587 schoenebeck 3168 const UID uid = { id, size };
588     return uid;
589 schoenebeck 3138 }
590    
591     static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
592     _Blob blob = _decodeBlob(p, end);
593     p = blob.p;
594     end = blob.end;
595    
596     UIDChain chain;
597     while (p < end) {
598     const UID uid = _popUIDBlob(p, end);
599     chain.push_back(uid);
600     }
601     assert(!chain.empty());
602     return chain;
603     }
604    
605 schoenebeck 3146 static Member _popMemberBlob(const char*& p, const char* end) {
606 schoenebeck 3138 _Blob blob = _decodeBlob(p, end, false);
607     p = blob.p;
608     end = blob.end;
609    
610     Member m;
611     if (p >= end) return m;
612    
613     m.m_uid = _popUIDBlob(p, end);
614     m.m_offset = _popIntBlob<size_t>(p, end);
615     m.m_name = _popStringBlob(p, end);
616     m.m_type = _popDataTypeBlob(p, end);
617     assert(m.type());
618     assert(!m.name().empty());
619 schoenebeck 3146 assert(m.uid().isValid());
620 schoenebeck 3138 return m;
621     }
622    
623     static std::vector<Member> _popMembersBlob(const char*& p, const char* end) {
624     _Blob blob = _decodeBlob(p, end, false);
625     p = blob.p;
626     end = blob.end;
627    
628     std::vector<Member> members;
629     while (p < end) {
630     const Member member = _popMemberBlob(p, end);
631     if (member)
632     members.push_back(member);
633     else
634     break;
635     }
636     return members;
637     }
638    
639 schoenebeck 3146 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj) {
640 schoenebeck 3138 const DataType& type = obj.type();
641     if (type.isPrimitive() && !type.isPointer()) {
642     obj.m_data.resize(type.size());
643     if (type.isInteger() || type.isEnum()) {
644     if (type.isSigned()) {
645     if (type.size() == 1)
646     _popIntBlob<int8_t>(p, end, obj.m_data);
647     else if (type.size() == 2)
648     _popIntBlob<int16_t>(p, end, obj.m_data);
649     else if (type.size() == 4)
650     _popIntBlob<int32_t>(p, end, obj.m_data);
651     else if (type.size() == 8)
652     _popIntBlob<int64_t>(p, end, obj.m_data);
653     else
654     assert(false /* unknown signed int type size */);
655     } else {
656     if (type.size() == 1)
657     _popIntBlob<uint8_t>(p, end, obj.m_data);
658     else if (type.size() == 2)
659     _popIntBlob<uint16_t>(p, end, obj.m_data);
660     else if (type.size() == 4)
661     _popIntBlob<uint32_t>(p, end, obj.m_data);
662     else if (type.size() == 8)
663     _popIntBlob<uint64_t>(p, end, obj.m_data);
664     else
665     assert(false /* unknown unsigned int type size */);
666     }
667     } else if (type.isReal()) {
668     if (type.size() == sizeof(float))
669     _popRealBlob<float>(p, end, obj.m_data);
670     else if (type.size() == sizeof(double))
671     _popRealBlob<double>(p, end, obj.m_data);
672     else
673     assert(false /* unknown floating point type */);
674     } else if (type.isBool()) {
675     _popIntBlob<uint8_t>(p, end, obj.m_data);
676     } else {
677     assert(false /* unknown primitive type */);
678     }
679    
680     } else {
681     // don't whine if the empty blob was not added on encoder side
682     _Blob blob = _decodeBlob(p, end, false);
683     p = blob.p;
684     end = blob.end;
685     }
686     }
687    
688 schoenebeck 3146 static Object _popObjectBlob(const char*& p, const char* end) {
689 schoenebeck 3138 _Blob blob = _decodeBlob(p, end, false);
690     p = blob.p;
691     end = blob.end;
692    
693     Object obj;
694     if (p >= end) return obj;
695    
696     obj.m_type = _popDataTypeBlob(p, end);
697     obj.m_version = _popIntBlob<Version>(p, end);
698     obj.m_minVersion = _popIntBlob<Version>(p, end);
699     obj.m_uid = _popUIDChainBlob(p, end);
700     obj.m_members = _popMembersBlob(p, end);
701     _popPrimitiveValue(p, end, obj);
702     assert(obj.type());
703     return obj;
704     }
705    
706     void Archive::_popObjectsBlob(const char*& p, const char* end) {
707     _Blob blob = _decodeBlob(p, end, false);
708     p = blob.p;
709     end = blob.end;
710    
711     if (p >= end)
712     throw Exception("Decode Error: Premature end of objects blob");
713    
714     while (true) {
715     const Object obj = _popObjectBlob(p, end);
716     if (!obj) break;
717     m_allObjects[obj.uid()] = obj;
718     }
719     }
720    
721     void Archive::_popRootBlob(const char*& p, const char* end) {
722     _Blob blob = _decodeBlob(p, end, false);
723     p = blob.p;
724     end = blob.end;
725    
726     if (p >= end)
727     throw Exception("Decode Error: Premature end of root blob");
728    
729     // just in case this encoding format will be extended in future
730     // (currently not used)
731     const int formatMinorVersion = _popIntBlob<int>(p, end);
732    
733     m_root = _popUIDBlob(p, end);
734     if (!m_root)
735     throw Exception("Decode Error: No root object");
736    
737     _popObjectsBlob(p, end);
738     if (!m_allObjects[m_root])
739     throw Exception("Decode Error: Missing declared root object");
740 schoenebeck 3156
741     m_name = _popStringBlob(p, end);
742     m_comment = _popStringBlob(p, end);
743     m_timeCreated = _popTimeBlob(p, end);
744     m_timeModified = _popTimeBlob(p, end);
745 schoenebeck 3138 }
746    
747     void Archive::decode(const RawData& data) {
748     m_rawData = data;
749     m_allObjects.clear();
750 schoenebeck 3150 m_isModified = false;
751 schoenebeck 3156 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
752 schoenebeck 3138 const char* p = (const char*) &data[0];
753     const char* end = p + data.size();
754     if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
755     throw Exception("Decode Error: Magic start missing!");
756     p += strlen(MAGIC_START);
757     _popRootBlob(p, end);
758     }
759    
760     void Archive::decode(const uint8_t* data, size_t size) {
761     RawData rawData;
762     rawData.resize(size);
763     memcpy(&rawData[0], data, size);
764     decode(rawData);
765     }
766    
767 schoenebeck 3150 const RawData& Archive::rawData() {
768     if (m_isModified) encode();
769     return m_rawData;
770     }
771    
772 schoenebeck 3138 String Archive::rawDataFormat() const {
773     return MAGIC_START;
774     }
775    
776 schoenebeck 3150 bool Archive::isModified() const {
777     return m_isModified;
778     }
779    
780 schoenebeck 3138 void Archive::clear() {
781     m_allObjects.clear();
782     m_operation = OPERATION_NONE;
783     m_root = NO_UID;
784     m_rawData.clear();
785 schoenebeck 3150 m_isModified = false;
786 schoenebeck 3156 m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
787 schoenebeck 3138 }
788    
789 schoenebeck 3156 String Archive::name() const {
790     return m_name;
791     }
792    
793     void Archive::setName(String name) {
794     if (m_name == name) return;
795     m_name = name;
796     m_isModified = true;
797     }
798    
799     String Archive::comment() const {
800     return m_comment;
801     }
802    
803     void Archive::setComment(String comment) {
804     if (m_comment == comment) return;
805     m_comment = comment;
806     m_isModified = true;
807     }
808    
809     static tm _convertTimeStamp(const time_t& time, time_base_t base) {
810     tm* pTm;
811     switch (base) {
812     case LOCAL_TIME:
813     pTm = localtime(&time);
814     break;
815     case UTC_TIME:
816     pTm = gmtime(&time);
817     break;
818     default:
819     throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
820     }
821     if (!pTm)
822     throw Exception("Failed assembling time stamp structure");
823     return *pTm;
824     }
825    
826     time_t Archive::timeStampCreated() const {
827     return m_timeCreated;
828     }
829    
830     time_t Archive::timeStampModified() const {
831     return m_timeModified;
832     }
833    
834     tm Archive::dateTimeCreated(time_base_t base) const {
835     return _convertTimeStamp(m_timeCreated, base);
836     }
837    
838     tm Archive::dateTimeModified(time_base_t base) const {
839     return _convertTimeStamp(m_timeModified, base);
840     }
841    
842 schoenebeck 3153 void Archive::removeMember(Object& parent, const Member& member) {
843     parent.remove(member);
844     m_isModified = true;
845     }
846    
847 schoenebeck 3138 void Archive::remove(const Object& obj) {
848 schoenebeck 3153 //FIXME: Should traverse from root object and remove all members associated with this object
849 schoenebeck 3138 if (!obj.uid()) return;
850     m_allObjects.erase(obj.uid());
851 schoenebeck 3150 m_isModified = true;
852 schoenebeck 3138 }
853    
854     Object& Archive::objectByUID(const UID& uid) {
855     return m_allObjects[uid];
856     }
857    
858 schoenebeck 3150 void Archive::setEnumValue(Object& object, uint64_t value) {
859     if (!object) return;
860     if (!object.type().isEnum())
861     throw Exception("Not an enum data type");
862     Object* pObject = &object;
863     if (object.type().isPointer()) {
864     Object& obj = objectByUID(object.uid(1));
865     if (!obj) return;
866     pObject = &obj;
867     }
868     const int nativeEnumSize = sizeof(enum operation_t);
869     DataType& type = const_cast<DataType&>( pObject->type() );
870     // original serializer ("sender") might have had a different word size
871     // than this machine, adjust type object in this case
872     if (type.size() != nativeEnumSize) {
873     type.m_size = nativeEnumSize;
874     }
875     pObject->m_data.resize(type.size());
876     void* ptr = &pObject->m_data[0];
877     if (type.size() == 1)
878     *(uint8_t*)ptr = (uint8_t)value;
879     else if (type.size() == 2)
880     *(uint16_t*)ptr = (uint16_t)value;
881     else if (type.size() == 4)
882     *(uint32_t*)ptr = (uint32_t)value;
883     else if (type.size() == 8)
884     *(uint64_t*)ptr = (uint64_t)value;
885     else
886     assert(false /* unknown enum type size */);
887     m_isModified = true;
888     }
889    
890     void Archive::setIntValue(Object& object, int64_t value) {
891     if (!object) return;
892     if (!object.type().isInteger())
893     throw Exception("Not an integer data type");
894     Object* pObject = &object;
895     if (object.type().isPointer()) {
896     Object& obj = objectByUID(object.uid(1));
897     if (!obj) return;
898     pObject = &obj;
899     }
900     const DataType& type = pObject->type();
901     pObject->m_data.resize(type.size());
902     void* ptr = &pObject->m_data[0];
903     if (type.isSigned()) {
904     if (type.size() == 1)
905     *(int8_t*)ptr = (int8_t)value;
906     else if (type.size() == 2)
907     *(int16_t*)ptr = (int16_t)value;
908     else if (type.size() == 4)
909     *(int32_t*)ptr = (int32_t)value;
910     else if (type.size() == 8)
911     *(int64_t*)ptr = (int64_t)value;
912     else
913     assert(false /* unknown signed int type size */);
914     } else {
915     if (type.size() == 1)
916     *(uint8_t*)ptr = (uint8_t)value;
917     else if (type.size() == 2)
918     *(uint16_t*)ptr = (uint16_t)value;
919     else if (type.size() == 4)
920     *(uint32_t*)ptr = (uint32_t)value;
921     else if (type.size() == 8)
922     *(uint64_t*)ptr = (uint64_t)value;
923     else
924     assert(false /* unknown unsigned int type size */);
925     }
926     m_isModified = true;
927     }
928    
929     void Archive::setRealValue(Object& object, double value) {
930     if (!object) return;
931     if (!object.type().isReal())
932     throw Exception("Not a real data type");
933     Object* pObject = &object;
934     if (object.type().isPointer()) {
935     Object& obj = objectByUID(object.uid(1));
936     if (!obj) return;
937     pObject = &obj;
938     }
939     const DataType& type = pObject->type();
940     pObject->m_data.resize(type.size());
941     void* ptr = &pObject->m_data[0];
942     if (type.size() == sizeof(float))
943     *(float*)ptr = (float)value;
944     else if (type.size() == sizeof(double))
945     *(double*)ptr = (double)value;
946     else
947     assert(false /* unknown real type size */);
948     m_isModified = true;
949     }
950    
951     void Archive::setBoolValue(Object& object, bool value) {
952     if (!object) return;
953     if (!object.type().isBool())
954     throw Exception("Not a bool data type");
955     Object* pObject = &object;
956     if (object.type().isPointer()) {
957     Object& obj = objectByUID(object.uid(1));
958     if (!obj) return;
959     pObject = &obj;
960     }
961     const DataType& type = pObject->type();
962     pObject->m_data.resize(type.size());
963     bool* ptr = (bool*)&pObject->m_data[0];
964     *ptr = value;
965     m_isModified = true;
966     }
967    
968     void Archive::setAutoValue(Object& object, String value) {
969     if (!object) return;
970     const DataType& type = object.type();
971     if (type.isInteger())
972     setIntValue(object, atoll(value.c_str()));
973     else if (type.isReal())
974     setRealValue(object, atof(value.c_str()));
975     else if (type.isBool())
976     setBoolValue(object, atof(value.c_str()));
977     else if (type.isEnum())
978     setEnumValue(object, atoll(value.c_str()));
979     else
980     throw Exception("Not a primitive data type");
981     }
982    
983     String Archive::valueAsString(const Object& object) {
984     if (!object)
985     throw Exception("Invalid object");
986     if (object.type().isClass())
987     throw Exception("Object is class type");
988     const Object* pObject = &object;
989     if (object.type().isPointer()) {
990     const Object& obj = objectByUID(object.uid(1));
991     if (!obj) return "";
992     pObject = &obj;
993     }
994     return _primitiveObjectValueToString(*pObject);
995     }
996    
997 schoenebeck 3138 // *************** Archive::Syncer ***************
998     // *
999    
1000     Archive::Syncer::Syncer(Archive& dst, Archive& src)
1001     : m_dst(dst), m_src(src)
1002     {
1003     const Object srcRootObj = src.rootObject();
1004     const Object dstRootObj = dst.rootObject();
1005     if (!srcRootObj)
1006     throw Exception("No source root object!");
1007     if (!dstRootObj)
1008     throw Exception("Expected destination root object not found!");
1009     syncObject(dstRootObj, srcRootObj);
1010     }
1011    
1012     void Archive::Syncer::syncPrimitive(const Object& dstObj, const Object& srcObj) {
1013     assert(srcObj.rawData().size() == dstObj.type().size());
1014     void* pDst = (void*)dstObj.uid().id;
1015     memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
1016     }
1017    
1018     void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
1019     assert(dstObj.type().isPointer());
1020     assert(dstObj.type() == srcObj.type());
1021     const Object& pointedDstObject = m_dst.m_allObjects[dstObj.uid(1)];
1022     const Object& pointedSrcObject = m_src.m_allObjects[srcObj.uid(1)];
1023     syncObject(pointedDstObject, pointedSrcObject);
1024     }
1025    
1026     void Archive::Syncer::syncObject(const Object& dstObj, const Object& srcObj) {
1027     if (!dstObj || !srcObj) return; // end of recursion
1028     if (!dstObj.isVersionCompatibleTo(srcObj))
1029     throw Exception("Version incompatible (destination version " +
1030     ToString(dstObj.version()) + " [min. version " +
1031     ToString(dstObj.minVersion()) + "], source version " +
1032     ToString(srcObj.version()) + " [min. version " +
1033     ToString(srcObj.minVersion()) + "])");
1034     if (dstObj.type() != srcObj.type())
1035     throw Exception("Incompatible data structure type (destination type " +
1036     dstObj.type().asLongDescr() + " vs. source type " +
1037     srcObj.type().asLongDescr() + ")");
1038    
1039     // prevent syncing this object again, and thus also prevent endless
1040     // loop on data structures with cyclic relations
1041     m_dst.m_allObjects.erase(dstObj.uid());
1042    
1043     if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
1044     syncPrimitive(dstObj, srcObj);
1045     return; // end of recursion
1046     }
1047    
1048     if (dstObj.type().isPointer()) {
1049     syncPointer(dstObj, srcObj);
1050     return;
1051     }
1052    
1053     assert(dstObj.type().isClass());
1054     for (int iMember = 0; iMember < srcObj.members().size(); ++iMember) {
1055     const Member& srcMember = srcObj.members()[iMember];
1056     Member dstMember = dstMemberMatching(dstObj, srcObj, srcMember);
1057     if (!dstMember)
1058     throw Exception("Expected member missing in destination object");
1059     syncMember(dstMember, srcMember);
1060     }
1061     }
1062    
1063     Member Archive::Syncer::dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember) {
1064     Member dstMember = dstObj.memberNamed(srcMember.name());
1065     if (dstMember)
1066     return (dstMember.type() == srcMember.type()) ? dstMember : Member();
1067     std::vector<Member> members = dstObj.membersOfType(srcMember.type());
1068     if (members.size() <= 0)
1069     return Member();
1070     if (members.size() == 1)
1071     return members[0];
1072     for (int i = 0; i < members.size(); ++i)
1073     if (members[i].offset() == srcMember.offset())
1074     return members[i];
1075     const int srcSeqNr = srcObj.sequenceIndexOf(srcMember);
1076     assert(srcSeqNr >= 0); // should never happen, otherwise there is a bug
1077     for (int i = 0; i < members.size(); ++i) {
1078     const int dstSeqNr = dstObj.sequenceIndexOf(members[i]);
1079     if (dstSeqNr == srcSeqNr)
1080     return members[i];
1081     }
1082     return Member(); // give up!
1083     }
1084    
1085     void Archive::Syncer::syncMember(const Member& dstMember, const Member& srcMember) {
1086     assert(dstMember && srcMember);
1087     assert(dstMember.type() == srcMember.type());
1088     const Object dstObj = m_dst.m_allObjects[dstMember.uid()];
1089     const Object srcObj = m_src.m_allObjects[srcMember.uid()];
1090     syncObject(dstObj, srcObj);
1091     }
1092    
1093     // *************** Exception ***************
1094     // *
1095    
1096     void Exception::PrintMessage() {
1097     std::cout << "Serialization::Exception: " << Message << std::endl;
1098     }
1099    
1100     } // namespace Serialization

  ViewVC Help
Powered by ViewVC