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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3156 - (hide annotations) (download)
Mon May 8 17:18:07 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 36636 byte(s)
* class Archive: Added methods name() and setName().
* class Archive: Added methods comment() and setComment().
* class Archive: Added methods timeStampCreated(),
  timeStampModified(), dateTimeCreated() and
  dateTimeModified().
* Bumped version (4.0.0.svn18).

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

  ViewVC Help
Powered by ViewVC