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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3150 by schoenebeck, Fri May 5 18:42:06 2017 UTC revision 3333 by schoenebeck, Sat Jul 29 09:57:08 2017 UTC
# Line 27  Line 27 
27  #include <assert.h>  #include <assert.h>
28  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
29  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
30    #include <cxxabi.h>
31    
32  #include "helper.h"  #include "helper.h"
33    
34    #define LIBGIG_EPOCH_TIME ((time_t)0)
35    
36  namespace Serialization {  namespace Serialization {
37    
38      // *************** DataType ***************      // *************** DataType ***************
39      // *      // *
40    
41      static UID _createNullUID() {      static UID _createNullUID() {
42          return (UID) { NULL, 0 };          const UID uid = { NULL, 0 };
43            return uid;
44      }      }
45    
46      const UID NO_UID = _createNullUID();      const UID NO_UID = _createNullUID();
47    
48        /** @brief Check whether this is a valid unique identifier.
49         *
50         * Returns @c false if this UID can be considered an invalid unique
51         * identifier. This is for example the case if this UID object was not
52         * explicitly set to some certain meaningful unique identifier value, or if
53         * this UID object was intentionally assigned the constant @c NO_UID value.
54         * Both represent essentially an UID object which is all zero.
55         *
56         * Note that this class also implements the @c bool operator, both return
57         * the same boolean result.
58         */
59      bool UID::isValid() const {      bool UID::isValid() const {
60          return id != NULL && id != (void*)-1 && size;          return id != NULL && id != (void*)-1 && size;
61      }      }
# Line 48  namespace Serialization { Line 63  namespace Serialization {
63      // *************** DataType ***************      // *************** DataType ***************
64      // *      // *
65    
66        /** @brief Default constructor.
67         *
68         * Initializes a DataType object as being an "invalid" DataType object.
69         * Thus calling isValid(), after creating a DataType object with this
70         * constructor, would return @c false.
71         *
72         * To create a valid and meaningful DataType object instead, call the static
73         * function DataType::dataTypeOf() instead.
74         */
75      DataType::DataType() {      DataType::DataType() {
76          m_size = 0;          m_size = 0;
77          m_isPointer = false;          m_isPointer = false;
# Line 60  namespace Serialization { Line 84  namespace Serialization {
84          m_customTypeName = customType;          m_customTypeName = customType;
85      }      }
86    
87        /** @brief Check if this is a valid DataType object.
88         *
89         * Returns @c true if this DataType object is reflecting a valid data type.
90         * The default constructor creates DataType objects initialized to be
91         * "invalid" DataType objects by default. That way one can detect whether
92         * a DataType object was ever assigned to something meaningful.
93         *
94         * Note that this class also implements the @c bool operator, both return
95         * the same boolean result.
96         */
97      bool DataType::isValid() const {      bool DataType::isValid() const {
98          return m_size;          return m_size;
99      }      }
100    
101        /** @brief Whether this is reflecting a C/C++ pointer type.
102         *
103         * Returns @true if the respective native C/C++ object, member or variable
104         * (this DataType instance is reflecting) is a C/C++ pointer type.
105         */
106      bool DataType::isPointer() const {      bool DataType::isPointer() const {
107          return m_isPointer;          return m_isPointer;
108      }      }
109    
110        /** @brief Whether this is reflecting a C/C++ @c struct or @c class type.
111         *
112         * Returns @c true if the respective native C/C++ object, member or variable
113         * (this DataType instance is reflecting) is a C/C++ @c struct or @c class
114         * type.
115         *
116         * Note that in the following example:
117         * @code
118         * struct Foo {
119         *     int  a;
120         *     bool b;
121         * };
122         * Foo foo;
123         * Foo* pFoo;
124         * @endcode
125         * the DataType objects of both @c foo, as well as of the C/C++ pointer
126         * @c pFoo would both return @c true for isClass() here!
127         *
128         * @see isPointer()
129         */
130      bool DataType::isClass() const {      bool DataType::isClass() const {
131          return m_baseTypeName == "class";          return m_baseTypeName == "class";
132      }      }
133    
134        /** @brief Whether this is reflecting a fundamental C/C++ data type.
135         *
136         * Returns @c true if the respective native C/C++ object, member or variable
137         * (this DataType instance is reflecting) is a primitive, fundamental C/C++
138         * data type. Those are fundamental data types which are already predefined
139         * by the C/C++ language, for example: @c char, @c int, @c float, @c double,
140         * @c bool, but also @b any pointer types like @c int*, @c double**, but
141         * including pointers to user defined types like:
142         * @code
143         * struct Foo {
144         *     int  a;
145         *     bool b;
146         * };
147         * Foo* pFoo;
148         * @endcode
149         * So the DataType object of @c pFoo in the latter example would also return
150         * @c true for isPrimitive() here!
151         *
152         * @see isPointer()
153         */
154      bool DataType::isPrimitive() const {      bool DataType::isPrimitive() const {
155          return !isClass();          return !isClass();
156      }      }
157    
158        /** @brief Whether this is an integer C/C++ data type.
159         *
160         * Returns @c true if the respective native C/C++ object, member or variable
161         * (this DataType instance is reflecting) is a (fundamental, primitive)
162         * integer data type. So these are all @c int and @c unsigned @c int types
163         * of any size. It does not include floating point ("real") types though.
164         *
165         * You may use isSigned() to further check whether this data type allows
166         * negative numbers.
167         *
168         * Note that this method also returns @c true on integer pointer types!
169         *
170         * @see isPointer()
171         */
172      bool DataType::isInteger() const {      bool DataType::isInteger() const {
173          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
174                 m_baseTypeName.substr(0, 4) == "uint";                 m_baseTypeName.substr(0, 4) == "uint";
175      }      }
176    
177        /** @brief Whether this is a floating point based C/C++ data type.
178         *
179         * Returns @c true if the respective native C/C++ object, member or variable
180         * (this DataType instance is reflecting) is a (fundamental, primitive)
181         * floating point based data type. So these are currently the C/C++ @c float
182         * and @c double types. It does not include integer types though.
183         *
184         * Note that this method also returns @c true on @c float pointer and
185         * @c double pointer types!
186         *
187         * @see isPointer()
188         */
189      bool DataType::isReal() const {      bool DataType::isReal() const {
190          return m_baseTypeName.substr(0, 4) == "real";          return m_baseTypeName.substr(0, 4) == "real";
191      }      }
192    
193        /** @brief Whether this is a boolean C/C++ data type.
194         *
195         * Returns @c true if the respective native C/C++ object, member or variable
196         * (this DataType instance is reflecting) is a (fundamental, primitive)
197         * boolean data type. So this is the case for the C++ @c bool data type.
198         * It does not include integer or floating point types though.
199         *
200         * Note that this method also returns @c true on @c bool pointer types!
201         *
202         * @see isPointer()
203         */
204      bool DataType::isBool() const {      bool DataType::isBool() const {
205          return m_baseTypeName == "bool";          return m_baseTypeName == "bool";
206      }      }
207    
208        /** @brief Whether this is a C/C++ @c enum data type.
209         *
210         * Returns @c true if the respective native C/C++ object, member or variable
211         * (this DataType instance is reflecting) is a user defined enumeration
212         * data type. So this is the case for all C/C++ @c enum data types.
213         * It does not include integer (or even floating point) types though.
214         *
215         * Note that this method also returns @c true on @c enum pointer types!
216         *
217         * @see isPointer()
218         */
219      bool DataType::isEnum() const {      bool DataType::isEnum() const {
220          return m_baseTypeName == "enum";          return m_baseTypeName == "enum";
221      }      }
222    
223        /** @brief Whether this is a signed integer C/C++ data type.
224         *
225         * Returns @c true if the respective native C/C++ object, member or variable
226         * (this DataType instance is reflecting) is a (fundamental, primitive)
227         * signed integer data type. This is the case for are all @c unsigned
228         * @c int C/C++ types of any size. For all floating point ("real") based
229         * types this method returns @c false though!
230         *
231         * Note that this method also returns @c true on signed integer pointer
232         * types!
233         *
234         * @see isInteger();
235         */
236      bool DataType::isSigned() const {      bool DataType::isSigned() const {
237          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
238                 isReal();                 isReal();
239      }      }
240    
241        /** @brief Comparison for equalness.
242         *
243         * Returns @c true if the two DataType objects being compared can be
244         * considered to be "equal" C/C++ data types. They are considered to be
245         * equal if their underlying C/C++ data types are exactly identical. For
246         * example comparing @c int and @c unsigned int data types are considere to
247         * be @b not equal, since they are differently signed. Furthermore @c short
248         * @c int and @c long @c int would also not be considered to be equal, since
249         * they do have a different memory size. Additionally pointer type
250         * characteristic is compared as well. So a @c double type and @c double*
251         * type are also considered to be not equal data types and hence this method
252         * would return @c false.
253         *
254         * As an exception here, classes and structs with the same class/struct name
255         * but different sizes are also considered to be "equal". This relaxed
256         * requirement is necessary to retain backward compatiblity to older
257         * versions of the same native C++ classes/structs.
258         */
259      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
260          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
261                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
262                 m_size           == other.m_size &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
263                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
264      }      }
265    
266        /** @brief Comparison for inequalness.
267         *
268         * Returns the inverse result of what DataType::operator==() would return.
269         * So refer to the latter for more details.
270         */
271      bool DataType::operator!=(const DataType& other) const {      bool DataType::operator!=(const DataType& other) const {
272          return !operator==(other);          return !operator==(other);
273      }      }
274    
275        /** @brief Smaller than comparison.
276         *
277         * Returns @c true if this DataType object can be consider to be "smaller"
278         * than the @a other DataType object being compared with. This operator
279         * is actually quite arbitrarily implemented and may change at any time,
280         * and thus result for the same data types may change in future at any time.
281         *
282         * This operator is basically implemented for allowing this DataType class
283         * to be used with various standard template library (STL) classes, which
284         * require sorting operators to be implemented.
285         */
286      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
287          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
288                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
# Line 119  namespace Serialization { Line 293  namespace Serialization {
293                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)));
294      }      }
295    
296        /** @brief Greater than comparison.
297         *
298         * Returns @c true if this DataType object can be consider to be "greater"
299         * than the @a other DataType object being compared with. This operator
300         * is actually quite arbitrarily implemented and may change at any time,
301         * and thus result for the same data types may change in future at any time.
302         *
303         * This operator is basically implemented for allowing this DataType class
304         * to be used with various standard template library (STL) classes, which
305         * require sorting operators to be implemented.
306         */
307      bool DataType::operator>(const DataType& other) const {      bool DataType::operator>(const DataType& other) const {
308          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
309      }      }
310    
311        /** @brief Human readable long description for this data type.
312         *
313         * Returns a human readable long description for this data type, designed
314         * for the purpose for being displayed to the user. Note that the
315         * implementation for this method and thus the precise textual strings
316         * returned by this method, may change at any time. So you should not rely
317         * on precise strings for certain data types, and you should not use the
318         * return values of this method for comparing data types with each other.
319         *
320         * This class implements various comparison operators, so you should use
321         * them for comparing DataTypes objects instead.
322         *
323         * @see baseTypeName(), customTypeName()
324         */
325      String DataType::asLongDescr() const {      String DataType::asLongDescr() const {
         //TODO: Demangling of C++ raw type names  
326          String s = m_baseTypeName;          String s = m_baseTypeName;
327          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
328              s += " " + m_customTypeName;              s += " " + customTypeName(true);
329          if (isPointer())          if (isPointer())
330              s += " pointer";              s += " pointer";
331          return s;          return s;
332      }      }
333    
334        /** @brief The base type name of this data type.
335         *
336         * Returns a textual short string identifying the basic type of name of this
337         * data type. For example for a 32 bit signed integer data type this method
338         * would return @c "int32". For all user defined C/C++ @c enum types this
339         * method would return "enum". For all user defined C/C++ @c struct @b and
340         * @c class types this method would return "class" for both. Note that the
341         * precise user defined type name (of i.e. @c enum, @c struct and @c class
342         * types) is not included in the string returned by this method, use
343         * customTypeName() to retrieve that information instead.
344         *
345         * The precise textual strings returned by this method are guaranteed to
346         * retain equal with future versions of this framework. So you can rely on
347         * them for using the return values of this method for comparison tasks in
348         * your application. Note however that this class also implements various
349         * comparison operators.
350         *
351         * Further it is important to know that this method returns the same string
352         * for pointers and non-pointers of the same underlying data type. So in the
353         * following example:
354         * @code
355         * #include <stdint.h>
356         * uint64_t i;
357         * uint64_t* pi;
358         * @endcode
359         * this method would return for both @c i and @c pi the string @c "uint64" !
360         *
361         * @see isPointer(), customTypeName()
362         */
363        String DataType::baseTypeName() const {
364            return m_baseTypeName;
365        }
366    
367        /** @brief The user defined C/C++ data type name of this data type.
368         *
369         * Call this method on user defined C/C++ data types like @c enum, @c struct
370         * and @c class types to retrieve the user defined type name portion of
371         * those data types. Note that this method is only intended for such user
372         * defined data types. For all fundamental, primitive data types (like i.e.
373         * @c int) this method returns an empty string instead.
374         *
375         * This method takes an optional boolean argument @b demangle, which allows
376         * you define whether you are interested in the raw C++ type name or rather
377         * the demangled custom type name. By default this method returns the raw
378         * C++ type name. The raw C++ type name is the one that is actually used
379         * in the compiled binaries and should be preferred for comparions tasks.
380         * The demangled C++ type name is a human readable representation of the
381         * type name instead, which you may use for displaying the user defined type
382         * name portion to the user, however you should not use the demangled
383         * representation for comparison tasks.
384         *
385         * Note that in the following example:
386         * @code
387         * struct Foo {
388         *     int  a;
389         *     bool b;
390         * };
391         * Foo foo;
392         * Foo* pFoo;
393         * @endcode
394         * this method would return the same string for both @c foo and @c pFoo !
395         * In the latter example @c customTypeName(true) would return for both
396         * @c foo and @c pFoo the string @c "Foo" as return value of this method.
397         *
398         * @see isPointer(), baseTypeName()
399         */
400        String DataType::customTypeName(bool demangle) const {
401            if (!demangle) return m_customTypeName;
402            int status;
403            const char* result =
404                abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
405            return (status == 0) ? result : m_customTypeName;
406        }
407    
408      // *************** Member ***************      // *************** Member ***************
409      // *      // *
410    
411        /** @brief Default constructor.
412         *
413         * Initializes a Member object as being an "invalid" Member object.
414         * Thus calling isValid(), after creating a Member object with this
415         * constructor, would return @c false.
416         *
417         * You are currently not supposed to create (meaningful) Member objects on
418         * your own. This framework automatically create such Member objects for
419         * you instead.
420         *
421         * @see Object::members()
422         */
423      Member::Member() {      Member::Member() {
424          m_uid = NO_UID;          m_uid = NO_UID;
425          m_offset = 0;          m_offset = 0;
# Line 148  namespace Serialization { Line 432  namespace Serialization {
432          m_type = type;          m_type = type;
433      }      }
434    
435        /** @brief Unique identifier of this member instance.
436         *
437         * Returns the unique identifier of the original C/C++ member instance of
438         * your C++ class. It is important to know that this unique identifier is
439         * not meant to be unique for Member instances themselves, but it is rather
440         * meant to be unique for the original native C/C++ data these Member
441         * instances are representing. So that means no matter how many individual
442         * Member objects are created, as long as they are representing the same
443         * original native member variable of the same original native
444         * instance of your C++ class, then all those separately created Member
445         * objects return the same unique identifier here.
446         *
447         * @see UID for more details
448         */
449        UID Member::uid() const {
450            return m_uid;
451        }
452    
453        /** @brief Name of the member.
454         *
455         * Returns the name of the native C/C++ member variable as originally typed
456         * in its C++ source code. So in the following example:
457         * @code
458         * struct Foo {
459         *     int  a;
460         *     bool b;
461         *     double someValue;
462         * };
463         * @endcode
464         * this method would usually return @c "a" for the first member of object
465         * instances of your native C/C++ @c struct @c Foo, and this method would
466         * usually return @c "someValue" for its third member.
467         *
468         * Note that when you implement the @c serialize() method of your own C/C++
469         * clases or strucs, you are able to override defining the precise name of
470         * your members. In that case this method would of course return the member
471         * names as explicitly forced by you instead.
472         */
473        String Member::name() const {
474            return m_name;
475        }
476    
477        /** @brief Offset of member in its containing parent data structure.
478         *
479         * Returns the offset of this member (in bytes) within its containing parent
480         * user defined data structure or class. So in the following example:
481         * @code
482         * #include <stdint.h>
483         * struct Foo __attribute__ ((__packed__)) {
484         *     int32_t a;
485         *     bool b;
486         *     double c;
487         * };
488         * @endcode
489         * this method would typically return @c 0 for member @c a, @c 4 for member
490         * @c b and @c 5 for member @c c. As you have noted in the latter example,
491         * the structure @c Foo was declared to have "packed" data members. That
492         * means the compiler is instructed to add no memory spaces between the
493         * individual members. Because by default the compiler might add memory
494         * spaces between individual members to align them on certain memory address
495         * boundaries for increasing runtime performance while accessing the
496         * members. So if you declared the previous example without the "packed"
497         * attribute like:
498         * @code
499         * #include <stdint.h>
500         * struct Foo {
501         *     int32_t a;
502         *     bool b;
503         *     double c;
504         * };
505         * @endcode
506         * then this method would usually return a different offset for members
507         * @c b and @c c instead. For most 64 bit architectures this example would
508         * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
509         * for member @c c.
510         */
511        size_t Member::offset() const {
512            return m_offset;
513        }
514    
515        /** @brief C/C++ Data type of this member.
516         *
517         * Returns the precise data type of the original native C/C++ member.
518         */
519        const DataType& Member::type() const {
520            return m_type;
521        }
522    
523        /** @brief Check if this is a valid Member object.
524         *
525         * Returns @c true if this Member object is reflecting a "valid" member
526         * object. The default constructor creates Member objects initialized to be
527         * "invalid" Member objects by default. That way one can detect whether
528         * a Member object was ever assigned to something meaningful.
529         *
530         * Note that this class also implements the @c bool operator, both return
531         * the same boolean result value.
532         */
533      bool Member::isValid() const {      bool Member::isValid() const {
534          return m_uid && !m_name.empty() && m_type;          return m_uid && !m_name.empty() && m_type;
535      }      }
536    
537        /** @brief Comparison for equalness.
538         *
539         * Returns @c true if the two Member objects being compared can be
540         * considered to be "equal" C/C++ members. They are considered to be
541         * equal if their data type, member name, their offset within their parent
542         * containing C/C++ data structure, as well as their original native C/C++
543         * instance were exactly identical.
544         */
545      bool Member::operator==(const Member& other) const {      bool Member::operator==(const Member& other) const {
546          return m_uid    == other.m_uid &&          return m_uid    == other.m_uid &&
547                 m_offset == other.m_offset &&                 m_offset == other.m_offset &&
# Line 159  namespace Serialization { Line 549  namespace Serialization {
549                 m_type   == other.m_type;                 m_type   == other.m_type;
550      }      }
551    
552        /** @brief Comparison for inequalness.
553         *
554         * Returns the inverse result of what Member::operator==() would return.
555         * So refer to the latter for more details.
556         */
557      bool Member::operator!=(const Member& other) const {      bool Member::operator!=(const Member& other) const {
558          return !operator==(other);          return !operator==(other);
559      }      }
560    
561        /** @brief Smaller than comparison.
562         *
563         * Returns @c true if this Member object can be consider to be "smaller"
564         * than the @a other Member object being compared with. This operator
565         * is actually quite arbitrarily implemented and may change at any time,
566         * and thus result for the same member representations may change in
567         * future at any time.
568         *
569         * This operator is basically implemented for allowing this DataType class
570         * to be used with various standard template library (STL) classes, which
571         * require sorting operators to be implemented.
572         */
573      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
574          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
575                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
# Line 173  namespace Serialization { Line 580  namespace Serialization {
580                 m_type < other.m_type)));                 m_type < other.m_type)));
581      }      }
582    
583        /** @brief Greater than comparison.
584         *
585         * Returns @c true if this Member object can be consider to be "greater"
586         * than the @a other Member object being compared with. This operator
587         * is actually quite arbitrarily implemented and may change at any time,
588         * and thus result for the same member representations may change in
589         * future at any time.
590         *
591         * This operator is basically implemented for allowing this DataType class
592         * to be used with various standard template library (STL) classes, which
593         * require sorting operators to be implemented.
594         */
595      bool Member::operator>(const Member& other) const {      bool Member::operator>(const Member& other) const {
596          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
597      }      }
# Line 180  namespace Serialization { Line 599  namespace Serialization {
599      // *************** Object ***************      // *************** Object ***************
600      // *      // *
601    
602        /** @brief Default constructor (for an "invalid" Object).
603         *
604         * Initializes an Object instance as being an "invalid" Object.
605         * Thus calling isValid(), after creating an Object instance with this
606         * constructor, would return @c false.
607         *
608         * Usually you are not supposed to create (meaningful) Object instances on
609         * your own. They are typically constructed by the Archive class for you.
610         *
611         * @see Archive::rootObject(), Archive::objectByUID()
612         */
613      Object::Object() {      Object::Object() {
614          m_version = 0;          m_version = 0;
615          m_minVersion = 0;          m_minVersion = 0;
616      }      }
617    
618        /** @brief Constructor for a "meaningful" Object.
619         *
620         * Initializes a "meaningful" Object instance as being. Thus calling
621         * isValid(), after creating an Object instance with this constructor,
622         * should return @c true, provided that the arguments passed to this
623         * constructor construe a valid object representation.
624         *
625         * Usually you are not supposed to create (meaningful) Object instances on
626         * your own. They are typically constructed by the Archive class for you.
627         *
628         * @see Archive::rootObject(), Archive::objectByUID()
629         *
630         * @param uidChain - unique identifier chain of the object to be constructed
631         * @param type - C/C++ data type of the actual native object this abstract
632         *               Object instance should reflect after calling this
633         *               constructor
634         */
635      Object::Object(UIDChain uidChain, DataType type) {      Object::Object(UIDChain uidChain, DataType type) {
636          m_type = type;          m_type = type;
637          m_uid  = uidChain;          m_uid  = uidChain;
# Line 193  namespace Serialization { Line 640  namespace Serialization {
640          //m_data.resize(type.size());          //m_data.resize(type.size());
641      }      }
642    
643        /** @brief Check if this is a valid Object instance.
644         *
645         * Returns @c true if this Object instance is reflecting a "valid" Object.
646         * The default constructor creates Object instances initialized to be
647         * "invalid" Objects by default. That way one can detect whether an Object
648         * instance was ever assigned to something meaningful.
649         *
650         * Note that this class also implements the @c bool operator, both return
651         * the same boolean result value.
652         */
653      bool Object::isValid() const {      bool Object::isValid() const {
654          return m_type && !m_uid.empty();          return m_type && !m_uid.empty();
655      }      }
656    
657        /** @brief Unique identifier of this Object.
658         *
659         * Returns the unique identifier for the original native C/C++ data this
660         * abstract Object instance is reflecting. If this Object is representing
661         * a C/C++ pointer (of first degree) then @c uid() (or @c uid(0) ) returns
662         * the unique identifier of the pointer itself, whereas @c uid(1) returns
663         * the unique identifier of the original C/C++ data that pointer was
664         * actually pointing to.
665         *
666         * @see UIDChain for more details about this overall topic.
667         */
668        UID Object::uid(int index) const {
669            return (index < m_uid.size()) ? m_uid[index] : NO_UID;
670        }
671    
672        /** @brief Unique identifier chain of this Object.
673         *
674         * Returns the entire unique identifier chain of this Object.
675         *
676         * @see uid() and UIDChain for more details about this overall topic.
677         */
678        const UIDChain& Object::uidChain() const {
679            return m_uid;
680        }
681    
682        /** @brief C/C++ data type this Object is reflecting.
683         *
684         * Returns the precise original C/C++ data type of the original native
685         * C/C++ object or data this Object instance is reflecting.
686         */
687        const DataType& Object::type() const {
688            return m_type;
689        }
690    
691        /** @brief Raw data of the original native C/C++ data.
692         *
693         * Returns the raw data value of the original C/C++ data this Object is
694         * reflecting. So the precise raw data value, layout and size is dependent
695         * to the precise C/C++ data type of the original native C/C++ data. However
696         * potentially required endian correction is already automatically applied
697         * for you. That means you can safely, directly C-cast the raw data returned
698         * by this method to the respective native C/C++ data type in order to
699         * access and use the value for some purpose, at least if the respective
700         * data is of any fundamental, primitive C/C++ data type, or also to a
701         * certain extent if the type is user defined @c enum type.
702         *
703         * However directly C-casting this raw data for user defined @c struct or
704         * @c class types is not possible. For those user defined data structures
705         * this method always returns empty raw data instead.
706         *
707         * Note however that there are more convenient methods in the Archive class
708         * to get the right value for the individual data types instead.
709         *
710         * @see Archive::valueAsInt(), Archive::valueAsReal(), Archive::valueAsBool(),
711         *      Archive::valueAsString()
712         */
713        const RawData& Object::rawData() const {
714            return m_data;
715        }
716    
717        /** @brief Version of original user defined C/C++ @c struct or @c class.
718         *
719         * In case this Object is reflecting a native C/C++ @c struct or @c class
720         * type, then this method returns the version of that native C/C++ @c struct
721         * or @c class layout or implementation. For primitive, fundamental C/C++
722         * data types the return value of this method has no meaning.
723         *
724         * @see Archive::setVersion() for more details about this overall topic.
725         */
726        Version Object::version() const {
727            return m_version;
728        }
729    
730        /** @brief Minimum version of original user defined C/C++ @c struct or @c class.
731         *
732         * In case this Object is reflecting a native C/C++ @c struct or @c class
733         * type, then this method returns the "minimum" version of that native C/C++
734         * @c struct or @c class layout or implementation which it may be compatible
735         * with. For primitive, fundamental C/C++ data types the return value of
736         * this method has no meaning.
737         *
738         * @see Archive::setVersion() and Archive::setMinVersion() for more details
739         *      about this overall topic.
740         */
741        Version Object::minVersion() const {
742            return m_minVersion;
743        }
744    
745        /** @brief All members of the original native C/C++ @c struct or @c class instance.
746         *
747         * In case this Object is reflecting a native C/C++ @c struct or @c class
748         * type, then this method returns all member variables of that original
749         * native C/C++ @c struct or @c class instance. For primitive, fundamental
750         * C/C++ data types this method returns an empty vector instead.
751         *
752         * Example:
753         * @code
754         * struct Foo {
755         *     int  a;
756         *     bool b;
757         *     double someValue;
758         * };
759         * @endcode
760         * Considering above's C++ code, a serialized Object representation of such
761         * a native @c Foo class would have 3 members @c a, @c b and @c someValue.
762         *
763         * Note that the respective serialize() method implementation of that
764         * fictional C++ @c struct @c Foo actually defines which members are going
765         * to be serialized and deserialized for instances of class @c Foo. So in
766         * practice the members returned by method members() here might return a
767         * different set of members as actually defined in the original C/C++ struct
768         * header declaration.
769         *
770         * The precise sequence of the members returned by this method here depends
771         * on the actual serialize() implementation of the user defined C/C++
772         * @c struct or @c class.
773         *
774         * @see Object::sequenceIndexOf() for more details about the precise order
775         *      of members returned by this method in the same way.
776         */
777        std::vector<Member>& Object::members() {
778            return m_members;
779        }
780    
781        /** @brief All members of the original native C/C++ @c struct or @c class instance (read only).
782         *
783         * Returns the same result as overridden members() method above, it just
784         * returns a read-only result instead. See above's method description for
785         * details for the return value of this method instead.
786         */
787        const std::vector<Member>& Object::members() const {
788            return m_members;
789        }
790    
791        /** @brief Comparison for equalness.
792         *
793         * Returns @c true if the two Object instances being compared can be
794         * considered to be "equal" native C/C++ object instances. They are
795         * considered to be equal if they are representing the same original
796         * C/C++ data instance, which is essentially the case if the original
797         * reflecting native C/C++ data are sharing the same memory address and
798         * memory size (thus the exact same memory space) and originally had the
799         * exact same native C/C++ types.
800         */
801      bool Object::operator==(const Object& other) const {      bool Object::operator==(const Object& other) const {
802          // ignoring all other member variables here          // ignoring all other member variables here
803          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 204  namespace Serialization { Line 805  namespace Serialization {
805                 m_type == other.m_type;                 m_type == other.m_type;
806      }      }
807    
808        /** @brief Comparison for inequalness.
809         *
810         * Returns the inverse result of what Object::operator==() would return.
811         * So refer to the latter for more details.
812         */
813      bool Object::operator!=(const Object& other) const {      bool Object::operator!=(const Object& other) const {
814          return !operator==(other);          return !operator==(other);
815      }      }
816    
817        /** @brief Smaller than comparison.
818         *
819         * Returns @c true if this Object instance can be consider to be "smaller"
820         * than the @a other Object instance being compared with. This operator
821         * is actually quite arbitrarily implemented and may change at any time,
822         * and thus result for the same Object representations may change in future
823         * at any time.
824         *
825         * This operator is basically implemented for allowing this DataType class
826         * to be used with various standard template library (STL) classes, which
827         * require sorting operators to be implemented.
828         */
829      bool Object::operator<(const Object& other) const {      bool Object::operator<(const Object& other) const {
830          // ignoring all other member variables here          // ignoring all other member variables here
831          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 216  namespace Serialization { Line 834  namespace Serialization {
834                 m_type < other.m_type);                 m_type < other.m_type);
835      }      }
836    
837        /** @brief Greater than comparison.
838         *
839         * Returns @c true if this Object instance can be consider to be "greater"
840         * than the @a other Object instance being compared with. This operator
841         * is actually quite arbitrarily implemented and may change at any time,
842         * and thus result for the same Object representations may change in future
843         * at any time.
844         *
845         * This operator is basically implemented for allowing this DataType class
846         * to be used with various standard template library (STL) classes, which
847         * require sorting operators to be implemented.
848         */
849      bool Object::operator>(const Object& other) const {      bool Object::operator>(const Object& other) const {
850          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
851      }      }
852    
853        /** @brief Check version compatibility between Object instances.
854         *
855         * Use this method to check whether the two original C/C++ instances those
856         * two Objects are reflecting, were using a C/C++ data type which are version
857         * compatible with each other. By default all C/C++ Objects are considered
858         * to be version compatible. They might only be version incompatible if you
859         * enforced a certain backward compatibility constraint with your
860         * serialize() method implementation of your custom C/C++ @c struct or
861         * @c class types.
862         *
863         * You must only call this method on two Object instances which are
864         * representing the same data type, for example if both Objects reflect
865         * instances of the same user defined C++ class. Calling this method on
866         * completely different data types does not cause an error or exception, but
867         * its result would simply be useless for any purpose.
868         *
869         * @see Archive::setVersion() for more details about this overall topic.
870         */
871      bool Object::isVersionCompatibleTo(const Object& other) const {      bool Object::isVersionCompatibleTo(const Object& other) const {
872          if (this->version() == other.version())          if (this->version() == other.version())
873              return true;              return true;
# Line 229  namespace Serialization { Line 877  namespace Serialization {
877              return other.minVersion() <= this->version();              return other.minVersion() <= this->version();
878      }      }
879    
880        void Object::setVersion(Version v) {
881            m_version = v;
882        }
883    
884        void Object::setMinVersion(Version v) {
885            m_minVersion = v;
886        }
887    
888        /** @brief Get the member of this Object with given name.
889         *
890         * In case this Object is reflecting a native C/C++ @c struct or @c class
891         * type, then this method returns the abstract reflection of the requested
892         * member variable of the original native C/C++ @c struct or @c class
893         * instance. For primitive, fundamental C/C++ data types this method always
894         * returns an "invalid" Member instance instead.
895         *
896         * Example:
897         * @code
898         * struct Foo {
899         *     int  a;
900         *     bool b;
901         *     double someValue;
902         * };
903         * @endcode
904         * Consider that you serialized the native C/C++ @c struct as shown in this
905         * example, and assuming that you implemented the respective serialize()
906         * method of this C++ @c struct to serialize all its members, then you might
907         * call memberNamed("someValue") to get the details of the third member in
908         * this example for instance. In case the passed @a name is an unknown
909         * member name, then this method will return an "invalid" Member object
910         * instead.
911         *
912         * @param name - original name of the sought serialized member variable of
913         *               this Object reflection
914         * @returns abstract reflection of the sought member variable
915         * @see Member::isValid(), Object::members()
916         */
917      Member Object::memberNamed(String name) const {      Member Object::memberNamed(String name) const {
918          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
919              if (m_members[i].name() == name)              if (m_members[i].name() == name)
# Line 236  namespace Serialization { Line 921  namespace Serialization {
921          return Member();          return Member();
922      }      }
923    
924        /** @brief Get the member of this Object with given unique identifier.
925         *
926         * This method behaves similar like method memberNamed() described above,
927         * but instead of searching for a member variable by name, it searches for
928         * a member with an abstract unique identifier instead. For primitive,
929         * fundamental C/C++ data types, for invalid or unknown unique identifiers,
930         * and for members which are actually not member instances of the original
931         * C/C++ @c struct or @c class instance this Object is reflecting, this
932         * method returns an "invalid" Member instance instead.
933         *
934         * @param uid - unique identifier of the member variable being sought
935         * @returns abstract reflection of the sought member variable
936         * @see Member::isValid(), Object::members(), Object::memberNamed()
937         */
938        Member Object::memberByUID(const UID& uid) const {
939            if (!uid) return Member();
940            for (int i = 0; i < m_members.size(); ++i)
941                if (m_members[i].uid() == uid)
942                    return m_members[i];
943            return Member();
944        }
945    
946      void Object::remove(const Member& member) {      void Object::remove(const Member& member) {
947          for (int i = 0; i < m_members.size(); ++i) {          for (int i = 0; i < m_members.size(); ++i) {
948              if (m_members[i] == member) {              if (m_members[i] == member) {
# Line 245  namespace Serialization { Line 952  namespace Serialization {
952          }          }
953      }      }
954    
955        /** @brief Get all members of this Object with given data type.
956         *
957         * In case this Object is reflecting a native C/C++ @c struct or @c class
958         * type, then this method returns all member variables of that original
959         * native C/C++ @c struct or @c class instance which are matching the given
960         * requested data @a type. If this Object is reflecting a primitive,
961         * fundamental data type, or if there are no members of this Object with the
962         * requested precise C/C++ data type, then this method returns an empty
963         * vector instead.
964         *
965         * @param type - the precise C/C++ data type of the sought member variables
966         *               of this Object
967         * @returns vector with abstract reflections of the sought member variables
968         * @see Object::members(), Object::memberNamed()
969         */
970      std::vector<Member> Object::membersOfType(const DataType& type) const {      std::vector<Member> Object::membersOfType(const DataType& type) const {
971          std::vector<Member> v;          std::vector<Member> v;
972          for (int i = 0; i < m_members.size(); ++i) {          for (int i = 0; i < m_members.size(); ++i) {
# Line 255  namespace Serialization { Line 977  namespace Serialization {
977          return v;          return v;
978      }      }
979    
980        /** @brief Serialization/deserialization sequence number of the requested member.
981         *
982         * Returns the precise serialization/deserialization sequence number of the
983         * requested @a member variable.
984         *
985         * Example:
986         * @code
987         * struct Foo {
988         *     int  a;
989         *     bool b;
990         *     double c;
991         *
992         *     void serialize(Serialization::Archive* archive);
993         * };
994         * @endcode
995         * Assuming the declaration of the user defined native C/C++ @c struct
996         * @c Foo above, and assuming the following implementation of serialize():
997         * @code
998         * #define SRLZ(member) \
999         *   archive->serializeMember(*this, member, #member);
1000         *
1001         * void Foo::serialize(Serialization::Archive* archive) {
1002         *     SRLZ(c);
1003         *     SRLZ(a);
1004         *     SRLZ(b);
1005         * }
1006         * @endcode
1007         * then @c sequenceIndexOf(obj.memberNamed("a")) returns 1,
1008         * @c sequenceIndexOf(obj.memberNamed("b")) returns 2, and
1009         * @c sequenceIndexOf(obj.memberNamed("c")) returns 0.
1010         */
1011      int Object::sequenceIndexOf(const Member& member) const {      int Object::sequenceIndexOf(const Member& member) const {
1012          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
1013              if (m_members[i] == member)              if (m_members[i] == member)
# Line 265  namespace Serialization { Line 1018  namespace Serialization {
1018      // *************** Archive ***************      // *************** Archive ***************
1019      // *      // *
1020    
1021        /** @brief Create an "empty" archive.
1022         *
1023         * This default constructor creates an "empty" archive which you then
1024         * subsequently for example might fill with serialized data like:
1025         * @code
1026         * Archive a;
1027         * a.serialize(&myRootObject);
1028         * @endcode
1029         * Or:
1030         * @code
1031         * Archive a;
1032         * a << myRootObject;
1033         * @endcode
1034         * Or you might also subsequently assign an already existing non-empty
1035         * to this empty archive, which effectively clones the other
1036         * archive (deep copy) or call decode() later on to assign a previously
1037         * serialized raw data stream.
1038         */
1039      Archive::Archive() {      Archive::Archive() {
1040          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1041          m_root = NO_UID;          m_root = NO_UID;
1042          m_isModified = false;          m_isModified = false;
1043            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1044      }      }
1045    
1046        /** @brief Create and fill the archive with the given serialized raw data.
1047         *
1048         * This constructor decodes the given raw @a data and constructs a
1049         * (non-empty) Archive object according to that given serialized data
1050         * stream.
1051         *
1052         * After this constructor returned, you may then traverse the individual
1053         * objects by starting with accessing the rootObject() for example. Finally
1054         * you might call deserialize() to restore your native C++ objects with the
1055         * content of this archive.
1056         *
1057         * @param data - the previously serialized raw data stream to be decoded
1058         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1059         *         incompatible or corrupt data stream or format.
1060         */
1061      Archive::Archive(const RawData& data) {      Archive::Archive(const RawData& data) {
1062          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1063          m_root = NO_UID;          m_root = NO_UID;
1064          m_isModified = false;          m_isModified = false;
1065            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1066          decode(m_rawData);          decode(m_rawData);
1067      }      }
1068    
1069        /** @brief Create and fill the archive with the given serialized raw C-buffer data.
1070         *
1071         * This constructor essentially works like the constructor above, but just
1072         * uses another data type for the serialized raw data stream being passed to
1073         * this class.
1074         *
1075         * This constructor decodes the given raw @a data and constructs a
1076         * (non-empty) Archive object according to that given serialized data
1077         * stream.
1078         *
1079         * After this constructor returned, you may then traverse the individual
1080         * objects by starting with accessing the rootObject() for example. Finally
1081         * you might call deserialize() to restore your native C++ objects with the
1082         * content of this archive.
1083         *
1084         * @param data - the previously serialized raw data stream to be decoded
1085         * @param size - size of @a data in bytes
1086         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1087         *         incompatible or corrupt data stream or format.
1088         */
1089      Archive::Archive(const uint8_t* data, size_t size) {      Archive::Archive(const uint8_t* data, size_t size) {
1090          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1091          m_root = NO_UID;          m_root = NO_UID;
1092          m_isModified = false;          m_isModified = false;
1093            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1094          decode(data, size);          decode(data, size);
1095      }      }
1096    
1097      Archive::~Archive() {      Archive::~Archive() {
1098      }      }
1099    
1100        /** @brief Root C++ object of this archive.
1101         *
1102         * In case this is a non-empty Archive, then this method returns the so
1103         * called "root" C++ object. If this is an empty archive, then this method
1104         * returns an "invalid" Object instance instead.
1105         *
1106         * @see Archive::serialize() for more details about the "root" object concept.
1107         * @see Object for more details about the overall object reflection concept.
1108         * @returns reflection of the original native C++ root object
1109         */
1110      Object& Archive::rootObject() {      Object& Archive::rootObject() {
1111          return m_allObjects[m_root];          return m_allObjects[m_root];
1112      }      }
# Line 303  namespace Serialization { Line 1122  namespace Serialization {
1122          return _encodeBlob(s);          return _encodeBlob(s);
1123      }      }
1124    
1125        static String _encode(const time_t& time) {
1126            return _encodeBlob(ToString(time));
1127        }
1128    
1129      static String _encode(const DataType& type) {      static String _encode(const DataType& type) {
1130          String s;          String s;
1131          s += _encodeBlob(type.baseTypeName());          s += _encodeBlob(type.baseTypeName());
# Line 384  namespace Serialization { Line 1207  namespace Serialization {
1207          return s;          return s;
1208      }      }
1209    
1210        template<typename T>
1211        static T _primitiveObjectValueToNumber(const Object& obj) {
1212            T value = 0;
1213            const DataType& type = obj.type();
1214            const ID& id = obj.uid().id;
1215            void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1216            if (!obj.m_data.empty())
1217                assert(type.size() == obj.m_data.size());
1218            if (type.isPrimitive() && !type.isPointer()) {
1219                if (type.isInteger() || type.isEnum()) {
1220                    if (type.isSigned()) {
1221                        if (type.size() == 1)
1222                            value = (T)*(int8_t*)ptr;
1223                        else if (type.size() == 2)
1224                            value = (T)*(int16_t*)ptr;
1225                        else if (type.size() == 4)
1226                            value = (T)*(int32_t*)ptr;
1227                        else if (type.size() == 8)
1228                            value = (T)*(int64_t*)ptr;
1229                        else
1230                            assert(false /* unknown signed int type size */);
1231                    } else {
1232                        if (type.size() == 1)
1233                            value = (T)*(uint8_t*)ptr;
1234                        else if (type.size() == 2)
1235                            value = (T)*(uint16_t*)ptr;
1236                        else if (type.size() == 4)
1237                            value = (T)*(uint32_t*)ptr;
1238                        else if (type.size() == 8)
1239                            value = (T)*(uint64_t*)ptr;
1240                        else
1241                            assert(false /* unknown unsigned int type size */);
1242                    }
1243                } else if (type.isReal()) {
1244                    if (type.size() == sizeof(float))
1245                        value = (T)*(float*)ptr;
1246                    else if (type.size() == sizeof(double))
1247                        value = (T)*(double*)ptr;
1248                    else
1249                        assert(false /* unknown floating point type */);
1250                } else if (type.isBool()) {
1251                    value = (T)*(bool*)ptr;
1252                } else {
1253                    assert(false /* unknown primitive type */);
1254                }
1255            }
1256            return value;
1257        }
1258    
1259      static String _encodePrimitiveValue(const Object& obj) {      static String _encodePrimitiveValue(const Object& obj) {
1260          return _encodeBlob( _primitiveObjectValueToString(obj) );          return _encodeBlob( _primitiveObjectValueToString(obj) );
1261      }      }
# Line 418  namespace Serialization { Line 1290  namespace Serialization {
1290          s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));          s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1291          s += _encode(m_root);          s += _encode(m_root);
1292          s += _encode(m_allObjects);          s += _encode(m_allObjects);
1293            s += _encodeBlob(m_name);
1294            s += _encodeBlob(m_comment);
1295            s += _encode(m_timeCreated);
1296            s += _encode(m_timeModified);
1297          return _encodeBlob(s);          return _encodeBlob(s);
1298      }      }
1299    
1300      void Archive::encode() {      void Archive::encode() {
1301          m_rawData.clear();          m_rawData.clear();
1302          String s = MAGIC_START;          String s = MAGIC_START;
1303            m_timeModified = time(NULL);
1304            if (m_timeCreated == LIBGIG_EPOCH_TIME)
1305                m_timeCreated = m_timeModified;
1306          s += _encodeRootBlob();          s += _encodeRootBlob();
1307          m_rawData.resize(s.length() + 1);          m_rawData.resize(s.length() + 1);
1308          memcpy(&m_rawData[0], &s[0], s.length() + 1);          memcpy(&m_rawData[0], &s[0], s.length() + 1);
# Line 436  namespace Serialization { Line 1315  namespace Serialization {
1315      };      };
1316    
1317      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1318          if (!bThrow && p >= end)          if (!bThrow && p >= end) {
1319              return (_Blob) { p, end };              const _Blob blob =  { p, end };
1320                return blob;
1321            }
1322          size_t sz = 0;          size_t sz = 0;
1323          for (; true; ++p) {          for (; true; ++p) {
1324              if (p >= end)              if (p >= end)
# Line 452  namespace Serialization { Line 1333  namespace Serialization {
1333          ++p;          ++p;
1334          if (p + sz > end)          if (p + sz > end)
1335              throw Exception("Decode Error: Premature end of blob");              throw Exception("Decode Error: Premature end of blob");
1336          return (_Blob) { p, p + sz };          const _Blob blob = { p, p + sz };
1337            return blob;
1338      }      }
1339    
1340      template<typename T_int>      template<typename T_int>
# Line 527  namespace Serialization { Line 1409  namespace Serialization {
1409          return s;          return s;
1410      }      }
1411    
1412        static time_t _popTimeBlob(const char*& p, const char* end) {
1413            const uint64_t i = _popIntBlob<uint64_t>(p, end);
1414            return (time_t) i;
1415        }
1416    
1417      DataType _popDataTypeBlob(const char*& p, const char* end) {      DataType _popDataTypeBlob(const char*& p, const char* end) {
1418          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1419          p   = blob.p;          p   = blob.p;
# Line 551  namespace Serialization { Line 1438  namespace Serialization {
1438          const ID id = (ID) _popIntBlob<size_t>(p, end);          const ID id = (ID) _popIntBlob<size_t>(p, end);
1439          const size_t size = _popIntBlob<size_t>(p, end);          const size_t size = _popIntBlob<size_t>(p, end);
1440    
1441          return (UID) { id, size };          const UID uid = { id, size };
1442            return uid;
1443      }      }
1444    
1445      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
# Line 703  namespace Serialization { Line 1591  namespace Serialization {
1591          _popObjectsBlob(p, end);          _popObjectsBlob(p, end);
1592          if (!m_allObjects[m_root])          if (!m_allObjects[m_root])
1593              throw Exception("Decode Error: Missing declared root object");              throw Exception("Decode Error: Missing declared root object");
     }  
1594    
1595            m_name = _popStringBlob(p, end);
1596            m_comment = _popStringBlob(p, end);
1597            m_timeCreated = _popTimeBlob(p, end);
1598            m_timeModified = _popTimeBlob(p, end);
1599        }
1600    
1601        /** @brief Fill this archive with the given serialized raw data.
1602         *
1603         * Calling this method will decode the given raw @a data and constructs a
1604         * (non-empty) Archive object according to that given serialized @a data
1605         * stream.
1606         *
1607         * After this method returned, you may then traverse the individual
1608         * objects by starting with accessing the rootObject() for example. Finally
1609         * you might call deserialize() to restore your native C++ objects with the
1610         * content of this archive.
1611         *
1612         * @param data - the previously serialized raw data stream to be decoded
1613         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1614         *         incompatible or corrupt data stream or format.
1615         */
1616      void Archive::decode(const RawData& data) {      void Archive::decode(const RawData& data) {
1617          m_rawData = data;          m_rawData = data;
1618          m_allObjects.clear();          m_allObjects.clear();
1619          m_isModified = false;          m_isModified = false;
1620            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1621          const char* p   = (const char*) &data[0];          const char* p   = (const char*) &data[0];
1622          const char* end = p + data.size();          const char* end = p + data.size();
1623          if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))          if (memcmp(p, MAGIC_START, std::min(strlen(MAGIC_START), data.size())))
# Line 717  namespace Serialization { Line 1626  namespace Serialization {
1626          _popRootBlob(p, end);          _popRootBlob(p, end);
1627      }      }
1628    
1629        /** @brief Fill this archive with the given serialized raw C-buffer data.
1630         *
1631         * This method essentially works like the decode() method above, but just
1632         * uses another data type for the serialized raw data stream being passed to
1633         * this method.
1634         *
1635         * Calling this method will decode the given raw @a data and constructs a
1636         * (non-empty) Archive object according to that given serialized @a data
1637         * stream.
1638         *
1639         * After this method returned, you may then traverse the individual
1640         * objects by starting with accessing the rootObject() for example. Finally
1641         * you might call deserialize() to restore your native C++ objects with the
1642         * content of this archive.
1643         *
1644         * @param data - the previously serialized raw data stream to be decoded
1645         * @param size - size of @a data in bytes
1646         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1647         *         incompatible or corrupt data stream or format.
1648         */
1649      void Archive::decode(const uint8_t* data, size_t size) {      void Archive::decode(const uint8_t* data, size_t size) {
1650          RawData rawData;          RawData rawData;
1651          rawData.resize(size);          rawData.resize(size);
# Line 724  namespace Serialization { Line 1653  namespace Serialization {
1653          decode(rawData);          decode(rawData);
1654      }      }
1655    
1656        /** @brief Raw data stream of this archive content.
1657         *
1658         * Call this method to get a raw data stream for the current content of this
1659         * archive, which you may use to i.e. store on disk or send vie network to
1660         * another machine for deserializing there. This method only returns a
1661         * meaningful content if this is a non-empty archive, that is if you either
1662         * serialized with this Archive object or decoded a raw data stream to this
1663         * Archive object before. If this is an empty archive instead, then this
1664         * method simply returns an empty raw data stream (of size 0) instead.
1665         *
1666         * Note that whenever you call this method, the "modified" state of this
1667         * archive will be reset to @c false.
1668         *
1669         * @see isModified()
1670         */
1671      const RawData& Archive::rawData() {      const RawData& Archive::rawData() {
1672          if (m_isModified) encode();          if (m_isModified) encode();
1673          return m_rawData;          return m_rawData;
1674      }      }
1675    
1676        /** @brief Name of the encoding format used by this Archive class.
1677         *
1678         * This method returns the name of the encoding format used to encode
1679         * serialized raw data streams.
1680         */
1681      String Archive::rawDataFormat() const {      String Archive::rawDataFormat() const {
1682          return MAGIC_START;          return MAGIC_START;
1683      }      }
1684    
1685        /** @brief Whether this archive was modified.
1686         *
1687         * This method returns the current "modified" state of this archive. When
1688         * either decoding a previously serialized raw data stream or after
1689         * serializing native C++ objects to this archive the modified state will
1690         * initially be set to @c false. However whenever you are modifying the
1691         * abstract data model of this archive afterwards, for example by removing
1692         * objects from this archive by calling remove() or removeMember(), or by
1693         * altering object values for example by calling setIntValue(), then the
1694         * "modified" state of this archive will automatically be set to @c true.
1695         *
1696         * You can reset the "modified" state explicitly at any time, by calling
1697         * rawData().
1698         */
1699      bool Archive::isModified() const {      bool Archive::isModified() const {
1700          return m_isModified;          return m_isModified;
1701      }      }
1702    
1703        /** @brief Clear content of this archive.
1704         *
1705         * Drops the entire content of this archive and thus resets this archive
1706         * back to become an empty archive.
1707         */
1708      void Archive::clear() {      void Archive::clear() {
1709          m_allObjects.clear();          m_allObjects.clear();
1710          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1711          m_root = NO_UID;          m_root = NO_UID;
1712          m_rawData.clear();          m_rawData.clear();
1713          m_isModified = false;          m_isModified = false;
1714            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1715        }
1716    
1717        /** @brief Optional name of this archive.
1718         *
1719         * Returns the optional name of this archive that you might have assigned
1720         * to this archive before by calling setName(). If you haven't assigned any
1721         * name to this archive before, then this method simply returns an empty
1722         * string instead.
1723         */
1724        String Archive::name() const {
1725            return m_name;
1726        }
1727    
1728        /** @brief Assign a name to this archive.
1729         *
1730         * You may optionally assign an arbitrary name to this archive. The name
1731         * will be stored along with the archive, that is it will encoded with the
1732         * resulting raw data stream, and accordingly it will be decoded from the
1733         * raw data stream later on.
1734         *
1735         * @param name - arbitrary new name for this archive
1736         */
1737        void Archive::setName(String name) {
1738            if (m_name == name) return;
1739            m_name = name;
1740            m_isModified = true;
1741      }      }
1742    
1743        /** @brief Optional comments for this archive.
1744         *
1745         * Returns the optional comments for this archive that you might have
1746         * assigned to this archive before by calling setComment(). If you haven't
1747         * assigned any comment to this archive before, then this method simply
1748         * returns an empty string instead.
1749         */
1750        String Archive::comment() const {
1751            return m_comment;
1752        }
1753    
1754        /** @brief Assign a comment to this archive.
1755         *
1756         * You may optionally assign arbitrary comments to this archive. The comment
1757         * will be stored along with the archive, that is it will encoded with the
1758         * resulting raw data stream, and accordingly it will be decoded from the
1759         * raw data stream later on.
1760         *
1761         * @param comment - arbitrary new comment for this archive
1762         */
1763        void Archive::setComment(String comment) {
1764            if (m_comment == comment) return;
1765            m_comment = comment;
1766            m_isModified = true;
1767        }
1768    
1769        static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1770            tm* pTm;
1771            switch (base) {
1772                case LOCAL_TIME:
1773                    pTm = localtime(&time);
1774                    break;
1775                case UTC_TIME:
1776                    pTm = gmtime(&time);
1777                    break;
1778                default:
1779                    throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1780            }
1781            if (!pTm)
1782                throw Exception("Failed assembling time stamp structure");
1783            return *pTm;
1784        }
1785    
1786        /** @brief Date and time when this archive was initially created.
1787         *
1788         * Returns a UTC time stamp (date and time) when this archive was initially
1789         * created.
1790         */
1791        time_t Archive::timeStampCreated() const {
1792            return m_timeCreated;
1793        }
1794    
1795        /** @brief Date and time when this archive was modified for the last time.
1796         *
1797         * Returns a UTC time stamp (date and time) when this archive was modified
1798         * for the last time.
1799         */
1800        time_t Archive::timeStampModified() const {
1801            return m_timeModified;
1802        }
1803    
1804        /** @brief Date and time when this archive was initially created.
1805         *
1806         * Returns a calendar time information representing the date and time when
1807         * this archive was initially created. The optional @a base parameter may
1808         * be used to define to which time zone the returned data and time shall be
1809         * related to.
1810         *
1811         * @param base - (optional) time zone the result shall relate to, by default
1812         *               UTC time (Greenwhich Mean Time) is assumed instead
1813         */
1814        tm Archive::dateTimeCreated(time_base_t base) const {
1815            return _convertTimeStamp(m_timeCreated, base);
1816        }
1817    
1818        /** @brief Date and time when this archive was modified for the last time.
1819         *
1820         * Returns a calendar time information representing the date and time when
1821         * this archive has been modified for the last time. The optional @a base
1822         * parameter may be used to define to which time zone the returned date and
1823         * time shall be related to.
1824         *
1825         * @param base - (optional) time zone the result shall relate to, by default
1826         *               UTC time (Greenwhich Mean Time) is assumed instead
1827         */
1828        tm Archive::dateTimeModified(time_base_t base) const {
1829            return _convertTimeStamp(m_timeModified, base);
1830        }
1831    
1832        /** @brief Remove a member variable from the given object.
1833         *
1834         * Removes the member variable @a member from its containing object
1835         * @a parent and sets the modified state of this archive to @c true.
1836         * If the given @a parent object does not contain the given @a member then
1837         * this method does nothing.
1838         *
1839         * This method provides a means of "partial" deserialization. By removing
1840         * either objects or members from this archive before calling deserialize(),
1841         * only the remaining objects and remaining members will be restored by this
1842         * framework, all other data of your C++ classes remain untouched.
1843         *
1844         * @param parent - Object which contains @a member
1845         * @param member - member to be removed
1846         * @see isModified() for details about the modified state.
1847         * @see Object for more details about the overall object reflection concept.
1848         */
1849        void Archive::removeMember(Object& parent, const Member& member) {
1850            parent.remove(member);
1851            m_isModified = true;
1852        }
1853    
1854        /** @brief Remove an object from this archive.
1855         *
1856         * Removes the object @obj from this archive and sets the modified state of
1857         * this archive to @c true. If the passed object is either invalid, or does
1858         * not exist in this archive, then this method does nothing.
1859         *
1860         * This method provides a means of "partial" deserialization. By removing
1861         * either objects or members from this archive before calling deserialize(),
1862         * only the remaining objects and remaining members will be restored by this
1863         * framework, all other data of your C++ classes remain untouched.
1864         *
1865         * @param obj - the object to be removed from this archive
1866         * @see isModified() for details about the modified state.
1867         * @see Object for more details about the overall object reflection concept.
1868         */
1869      void Archive::remove(const Object& obj) {      void Archive::remove(const Object& obj) {
1870            //FIXME: Should traverse from root object and remove all members associated with this object
1871          if (!obj.uid()) return;          if (!obj.uid()) return;
1872          m_allObjects.erase(obj.uid());          m_allObjects.erase(obj.uid());
1873          m_isModified = true;          m_isModified = true;
1874      }      }
1875    
1876        /** @brief Access object by its unique identifier.
1877         *
1878         * Returns the object of this archive with the given unique identifier
1879         * @a uid. If the given @a uid is invalid, or if this archive does not
1880         * contain an object with the given unique identifier, then this method
1881         * returns an invalid object instead.
1882         *
1883         * @param uid - unique identifier of sought object
1884         * @see Object for more details about the overall object reflection concept.
1885         * @see Object::isValid() for valid/invalid objects
1886         */
1887      Object& Archive::objectByUID(const UID& uid) {      Object& Archive::objectByUID(const UID& uid) {
1888          return m_allObjects[uid];          return m_allObjects[uid];
1889      }      }
1890    
1891        /** @brief Set the current version for the given object.
1892         *
1893         * Essentially behaves like above's setVersion() method, it just uses the
1894         * abstract reflection data type instead for the respective @a object being
1895         * passed to this method. Refer to above's setVersion() documentation about
1896         * the precise behavior details of setVersion().
1897         *
1898         * @param object - object to set the current version for
1899         * @param v - new current version to set for @a object
1900         */
1901        void Archive::setVersion(Object& object, Version v) {
1902            if (!object) return;
1903            object.setVersion(v);
1904            m_isModified = true;
1905        }
1906    
1907        /** @brief Set the minimum version for the given object.
1908         *
1909         * Essentially behaves like above's setMinVersion() method, it just uses the
1910         * abstract reflection data type instead for the respective @a object being
1911         * passed to this method. Refer to above's setMinVersion() documentation
1912         * about the precise behavior details of setMinVersion().
1913         *
1914         * @param object - object to set the minimum version for
1915         * @param v - new minimum version to set for @a object
1916         */
1917        void Archive::setMinVersion(Object& object, Version v) {
1918            if (!object) return;
1919            object.setMinVersion(v);
1920            m_isModified = true;
1921        }
1922    
1923        /** @brief Set new value for given @c enum object.
1924         *
1925         * Sets the new @a value to the given @c enum @a object.
1926         *
1927         * @param object - the @c enum object to be changed
1928         * @param value - the new value to be assigned to the @a object
1929         * @throws Exception if @a object is not an @c enum type.
1930         */
1931      void Archive::setEnumValue(Object& object, uint64_t value) {      void Archive::setEnumValue(Object& object, uint64_t value) {
1932          if (!object) return;          if (!object) return;
1933          if (!object.type().isEnum())          if (!object.type().isEnum())
# Line 787  namespace Serialization { Line 1960  namespace Serialization {
1960          m_isModified = true;          m_isModified = true;
1961      }      }
1962    
1963        /** @brief Set new integer value for given integer object.
1964         *
1965         * Sets the new integer @a value to the given integer @a object. Currently
1966         * this framework handles any integer data type up to 64 bit. For larger
1967         * integer types an assertion failure will be raised.
1968         *
1969         * @param object - the integer object to be changed
1970         * @param value - the new value to be assigned to the @a object
1971         * @throws Exception if @a object is not an integer type.
1972         */
1973      void Archive::setIntValue(Object& object, int64_t value) {      void Archive::setIntValue(Object& object, int64_t value) {
1974          if (!object) return;          if (!object) return;
1975          if (!object.type().isInteger())          if (!object.type().isInteger())
# Line 826  namespace Serialization { Line 2009  namespace Serialization {
2009          m_isModified = true;          m_isModified = true;
2010      }      }
2011    
2012        /** @brief Set new floating point value for given floating point object.
2013         *
2014         * Sets the new floating point @a value to the given floating point
2015         * @a object. Currently this framework supports single precision @c float
2016         * and double precision @c double floating point data types. For all other
2017         * floating point types this method will raise an assertion failure.
2018         *
2019         * @param object - the floating point object to be changed
2020         * @param value - the new value to be assigned to the @a object
2021         * @throws Exception if @a object is not a floating point based type.
2022         */
2023      void Archive::setRealValue(Object& object, double value) {      void Archive::setRealValue(Object& object, double value) {
2024          if (!object) return;          if (!object) return;
2025          if (!object.type().isReal())          if (!object.type().isReal())
# Line 848  namespace Serialization { Line 2042  namespace Serialization {
2042          m_isModified = true;          m_isModified = true;
2043      }      }
2044    
2045        /** @brief Set new boolean value for given boolean object.
2046         *
2047         * Sets the new boolean @a value to the given boolean @a object.
2048         *
2049         * @param object - the boolean object to be changed
2050         * @param value - the new value to be assigned to the @a object
2051         * @throws Exception if @a object is not a boolean type.
2052         */
2053      void Archive::setBoolValue(Object& object, bool value) {      void Archive::setBoolValue(Object& object, bool value) {
2054          if (!object) return;          if (!object) return;
2055          if (!object.type().isBool())          if (!object.type().isBool())
# Line 865  namespace Serialization { Line 2067  namespace Serialization {
2067          m_isModified = true;          m_isModified = true;
2068      }      }
2069    
2070        /** @brief Automatically cast and assign appropriate value to object.
2071         *
2072         * This method automatically converts the given @a value from textual string
2073         * representation into the appropriate data format of the requested
2074         * @a object. So this method is a convenient way to change values of objects
2075         * in this archive with your applications in automated way, i.e. for
2076         * implementing an editor where the user is able to edit values of objects
2077         * in this archive by entering the values as text with a keyboard.
2078         *
2079         * @throws Exception if the passed @a object is not a fundamental, primitive
2080         *         data type or if the provided textual value cannot be converted
2081         *         into an appropriate value for the requested object.
2082         */
2083      void Archive::setAutoValue(Object& object, String value) {      void Archive::setAutoValue(Object& object, String value) {
2084          if (!object) return;          if (!object) return;
2085          const DataType& type = object.type();          const DataType& type = object.type();
# Line 872  namespace Serialization { Line 2087  namespace Serialization {
2087              setIntValue(object, atoll(value.c_str()));              setIntValue(object, atoll(value.c_str()));
2088          else if (type.isReal())          else if (type.isReal())
2089              setRealValue(object, atof(value.c_str()));              setRealValue(object, atof(value.c_str()));
2090          else if (type.isBool())          else if (type.isBool()) {
2091              setBoolValue(object, atof(value.c_str()));              String val = toLowerCase(value);
2092          else if (type.isEnum())              if (val == "true" || val == "yes" || val == "1")
2093                    setBoolValue(object, true);
2094                else if (val == "false" || val == "no" || val == "0")
2095                    setBoolValue(object, false);
2096                else
2097                    setBoolValue(object, atof(value.c_str()));
2098            } else if (type.isEnum())
2099              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2100          else          else
2101              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
2102      }      }
2103    
2104        /** @brief Get value of object as string.
2105         *
2106         * Converts the current value of the given @a object into a textual string
2107         * and returns that string.
2108         *
2109         * @param object - object whose value shall be retrieved
2110         * @throws Exception if the given object is either invalid, or if the object
2111         *         is not a fundamental, primitive data type.
2112         */
2113      String Archive::valueAsString(const Object& object) {      String Archive::valueAsString(const Object& object) {
2114          if (!object)          if (!object)
2115              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 894  namespace Serialization { Line 2124  namespace Serialization {
2124          return _primitiveObjectValueToString(*pObject);          return _primitiveObjectValueToString(*pObject);
2125      }      }
2126    
2127        /** @brief Get integer value of object.
2128         *
2129         * Returns the current integer value of the requested integer @a object or
2130         * @c enum object.
2131         *
2132         * @param object - object whose value shall be retrieved
2133         * @throws Exception if the given object is either invalid, or if the object
2134         *         is neither an integer nor @c enum data type.
2135         */
2136        int64_t Archive::valueAsInt(const Object& object) {
2137            if (!object)
2138                throw Exception("Invalid object");
2139            if (!object.type().isInteger() && !object.type().isEnum())
2140                throw Exception("Object is neither an integer nor an enum");
2141            const Object* pObject = &object;
2142            if (object.type().isPointer()) {
2143                const Object& obj = objectByUID(object.uid(1));
2144                if (!obj) return 0;
2145                pObject = &obj;
2146            }
2147            return _primitiveObjectValueToNumber<int64_t>(*pObject);
2148        }
2149    
2150        /** @brief Get floating point value of object.
2151         *
2152         * Returns the current floating point value of the requested floating point
2153         * @a object.
2154         *
2155         * @param object - object whose value shall be retrieved
2156         * @throws Exception if the given object is either invalid, or if the object
2157         *         is not a floating point based type.
2158         */
2159        double Archive::valueAsReal(const Object& object) {
2160            if (!object)
2161                throw Exception("Invalid object");
2162            if (!object.type().isReal())
2163                throw Exception("Object is not an real type");
2164            const Object* pObject = &object;
2165            if (object.type().isPointer()) {
2166                const Object& obj = objectByUID(object.uid(1));
2167                if (!obj) return 0;
2168                pObject = &obj;
2169            }
2170            return _primitiveObjectValueToNumber<double>(*pObject);
2171        }
2172    
2173        /** @brief Get boolean value of object.
2174         *
2175         * Returns the current boolean value of the requested boolean @a object.
2176         *
2177         * @param object - object whose value shall be retrieved
2178         * @throws Exception if the given object is either invalid, or if the object
2179         *         is not a boolean data type.
2180         */
2181        bool Archive::valueAsBool(const Object& object) {
2182            if (!object)
2183                throw Exception("Invalid object");
2184            if (!object.type().isBool())
2185                throw Exception("Object is not a bool");
2186            const Object* pObject = &object;
2187            if (object.type().isPointer()) {
2188                const Object& obj = objectByUID(object.uid(1));
2189                if (!obj) return 0;
2190                pObject = &obj;
2191            }
2192            return _primitiveObjectValueToNumber<bool>(*pObject);
2193        }
2194    
2195      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2196      // *      // *
2197    
# Line 993  namespace Serialization { Line 2291  namespace Serialization {
2291      // *************** Exception ***************      // *************** Exception ***************
2292      // *      // *
2293    
2294        Exception::Exception() {
2295        }
2296    
2297        Exception::Exception(String format, ...) {
2298            va_list arg;
2299            va_start(arg, format);
2300            Message = assemble(format, arg);
2301            va_end(arg);
2302        }
2303    
2304        Exception::Exception(String format, va_list arg) {
2305            Message = assemble(format, arg);
2306        }
2307    
2308        /** @brief Print exception message to stdout.
2309         *
2310         * Prints the message of this Exception to the currently defined standard
2311         * output (that is to the terminal console for example).
2312         */
2313      void Exception::PrintMessage() {      void Exception::PrintMessage() {
2314          std::cout << "Serialization::Exception: " << Message << std::endl;          std::cout << "Serialization::Exception: " << Message << std::endl;
2315      }      }
2316    
2317        String Exception::assemble(String format, va_list arg) {
2318            char* buf = NULL;
2319            vasprintf(&buf, format.c_str(), arg);
2320            String s = buf;
2321            free(buf);
2322            return s;
2323        }
2324    
2325  } // namespace Serialization  } // namespace Serialization

Legend:
Removed from v.3150  
changed lines
  Added in v.3333

  ViewVC Help
Powered by ViewVC