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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3182 - (hide annotations) (download)
Sun May 14 20:40:02 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 41083 byte(s)
* Serialization framework: moved methods setVersion() and
  setMinVersion() from class Object to class Archive, and
  hide enum type operation_t from the public API.
* Bumped version (4.0.0.svn23).

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

  ViewVC Help
Powered by ViewVC