/[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 3159 by schoenebeck, Mon May 8 21:15:16 2017 UTC revision 3186 by schoenebeck, Wed May 17 15:55:18 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    
# Line 38  namespace Serialization { Line 39  namespace Serialization {
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 50  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 62  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      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
255          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
256                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
# Line 107  namespace Serialization { Line 258  namespace Serialization {
258                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
259      }      }
260    
261        /** @brief Comparison for inequalness.
262         *
263         * Returns the inverse result of what DataType::operator==() would return.
264         * So refer to the latter for more details.
265         */
266      bool DataType::operator!=(const DataType& other) const {      bool DataType::operator!=(const DataType& other) const {
267          return !operator==(other);          return !operator==(other);
268      }      }
269    
270        /** @brief Smaller than comparison.
271         *
272         * Returns @c true if this DataType object can be consider to be "smaller"
273         * than the @a other DataType object being compared with. This operator
274         * is actually quite arbitrarily implemented and may change at any time,
275         * and thus result for the same data types may change in future at any time.
276         *
277         * This operator is basically implemented for allowing this DataType class
278         * to be used with various standard template library (STL) classes, which
279         * require sorting operators to be implemented.
280         */
281      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
282          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
283                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
# Line 121  namespace Serialization { Line 288  namespace Serialization {
288                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)));
289      }      }
290    
291        /** @brief Greater than comparison.
292         *
293         * Returns @c true if this DataType object can be consider to be "greater"
294         * than the @a other DataType object being compared with. This operator
295         * is actually quite arbitrarily implemented and may change at any time,
296         * and thus result for the same data types may change in future at any time.
297         *
298         * This operator is basically implemented for allowing this DataType class
299         * to be used with various standard template library (STL) classes, which
300         * require sorting operators to be implemented.
301         */
302      bool DataType::operator>(const DataType& other) const {      bool DataType::operator>(const DataType& other) const {
303          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
304      }      }
305    
306        /** @brief Human readable long description for this data type.
307         *
308         * Returns a human readable long description for this data type, designed
309         * for the purpose for being displayed to the user. Note that the
310         * implementation for this method and thus the precise textual strings
311         * returned by this method, may change at any time. So you should not rely
312         * on precise strings for certain data types, and you should not use the
313         * return values of this method for comparing data types with each other.
314         *
315         * This class implements various comparison operators, so you should use
316         * them for comparing DataTypes objects instead.
317         *
318         * @see baseTypeName(), customTypeName()
319         */
320      String DataType::asLongDescr() const {      String DataType::asLongDescr() const {
         //TODO: Demangling of C++ raw type names  
321          String s = m_baseTypeName;          String s = m_baseTypeName;
322          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
323              s += " " + m_customTypeName;              s += " " + customTypeName(true);
324          if (isPointer())          if (isPointer())
325              s += " pointer";              s += " pointer";
326          return s;          return s;
327      }      }
328    
329        /** @brief The base type name of this data type.
330         *
331         * Returns a textual short string identifying the basic type of name of this
332         * data type. For example for a 32 bit signed integer data type this method
333         * would return @c "int32". For all user defined C/C++ @c enum types this
334         * method would return "enum". For all user defined C/C++ @c struct @b and
335         * @c class types this method would return "class" for both. Note that the
336         * precise user defined type name (of i.e. @c enum, @c struct and @c class
337         * types) is not included in the string returned by this method, use
338         * customTypeName() to retrieve that information instead.
339         *
340         * The precise textual strings returned by this method are guaranteed to
341         * retain equal with future versions of this framework. So you can rely on
342         * them for using the return values of this method for comparison tasks in
343         * your application. Note however that this class also implements various
344         * comparison operators.
345         *
346         * Further it is important to know that this method returns the same string
347         * for pointers and non-pointers of the same underlying data type. So in the
348         * following example:
349         * @code
350         * #include <stdint.h>
351         * uint64_t i;
352         * uint64_t* pi;
353         * @endcode
354         * this method would return for both @c i and @c pi the string @c "uint64" !
355         *
356         * @see isPointer(), customTypeName()
357         */
358        String DataType::baseTypeName() const {
359            return m_baseTypeName;
360        }
361    
362        /** @brief The user defined C/C++ data type name of this data type.
363         *
364         * Call this method on user defined C/C++ data types like @c enum, @c struct
365         * and @c class types to retrieve the user defined type name portion of
366         * those data types. Note that this method is only intended for such user
367         * defined data types. For all fundamental, primitive data types (like i.e.
368         * @c int) this method returns an empty string instead.
369         *
370         * This method takes an optional boolean argument @b demangle, which allows
371         * you define whether you are interested in the raw C++ type name or rather
372         * the demangled custom type name. By default this method returns the raw
373         * C++ type name. The raw C++ type name is the one that is actually used
374         * in the compiled binaries and should be preferred for comparions tasks.
375         * The demangled C++ type name is a human readable representation of the
376         * type name instead, which you may use for displaying the user defined type
377         * name portion to the user, however you should not use the demangled
378         * representation for comparison tasks.
379         *
380         * Note that in the following example:
381         * @code
382         * struct Foo {
383         *     int  a;
384         *     bool b;
385         * };
386         * Foo foo;
387         * Foo* pFoo;
388         * @endcode
389         * this method would return the same string for both @c foo and @c pFoo !
390         * In the latter example @c customTypeName(true) would return for both
391         * @c foo and @c pFoo the string @c "Foo" as return value of this method.
392         *
393         * @see isPointer(), baseTypeName()
394         */
395        String DataType::customTypeName(bool demangle) const {
396            if (!demangle) return m_customTypeName;
397            int status;
398            const char* result =
399                abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
400            return (status == 0) ? result : m_customTypeName;
401        }
402    
403      // *************** Member ***************      // *************** Member ***************
404      // *      // *
405    
406        /** @brief Default constructor.
407         *
408         * Initializes a Member object as being an "invalid" Member object.
409         * Thus calling isValid(), after creating a Member object with this
410         * constructor, would return @c false.
411         *
412         * You are currently not supposed to create (meaningful) Member objects on
413         * your own. This framework automatically create such Member objects for
414         * you instead.
415         *
416         * @see Object::members()
417         */
418      Member::Member() {      Member::Member() {
419          m_uid = NO_UID;          m_uid = NO_UID;
420          m_offset = 0;          m_offset = 0;
# Line 150  namespace Serialization { Line 427  namespace Serialization {
427          m_type = type;          m_type = type;
428      }      }
429    
430        /** @brief Unique identifier of this member instance.
431         *
432         * Returns the unique identifier of the original C/C++ member instance of
433         * your C++ class. It is important to know that this unique identifier is
434         * not meant to be unique for Member instances themselves, but it is rather
435         * meant to be unique for the original native C/C++ data these Member
436         * instances are representing. So that means no matter how many individual
437         * Member objects are created, as long as they are representing the same
438         * original native member variable of the same original native
439         * instance of your C++ class, then all those separately created Member
440         * objects return the same unique identifier here.
441         *
442         * @see UID for more details
443         */
444        UID Member::uid() const {
445            return m_uid;
446        }
447    
448        /** @brief Name of the member.
449         *
450         * Returns the name of the native C/C++ member variable as originally typed
451         * in its C++ source code. So in the following example:
452         * @code
453         * struct Foo {
454         *     int  a;
455         *     bool b;
456         *     double someValue;
457         * };
458         * @endcode
459         * this method would usually return @c "a" for the first member of object
460         * instances of your native C/C++ @c struct @c Foo, and this method would
461         * usually return @c "someValue" for its third member.
462         *
463         * Note that when you implement the @c serialize() method of your own C/C++
464         * clases or strucs, you are able to override defining the precise name of
465         * your members. In that case this method would of course return the member
466         * names as explicitly forced by you instead.
467         */
468        String Member::name() const {
469            return m_name;
470        }
471    
472        /** @brief Offset of member in its containing parent data structure.
473         *
474         * Returns the offset of this member (in bytes) within its containing parent
475         * user defined data structure or class. So in the following example:
476         * @code
477         * #include <stdint.h>
478         * struct Foo __attribute__ ((__packed__)) {
479         *     int32_t a;
480         *     bool b;
481         *     double c;
482         * };
483         * @endcode
484         * this method would typically return @c 0 for member @c a, @c 4 for member
485         * @c b and @c 5 for member @c c. As you have noted in the latter example,
486         * the structure @c Foo was declared to have "packed" data members. That
487         * means the compiler is instructed to add no memory spaces between the
488         * individual members. Because by default the compiler might add memory
489         * spaces between individual members to align them on certain memory address
490         * boundaries for increasing runtime performance while accessing the
491         * members. So if you declared the previous example without the "packed"
492         * attribute like:
493         * @code
494         * #include <stdint.h>
495         * struct Foo {
496         *     int32_t a;
497         *     bool b;
498         *     double c;
499         * };
500         * @endcode
501         * then this method would usually return a different offset for members
502         * @c b and @c c instead. For most 64 bit architectures this example would
503         * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
504         * for member @c c.
505         */
506        size_t Member::offset() const {
507            return m_offset;
508        }
509    
510        /** @brief C/C++ Data type of this member.
511         *
512         * Returns the precise data type of the original native C/C++ member.
513         */
514        const DataType& Member::type() const {
515            return m_type;
516        }
517    
518        /** @brief Check if this is a valid Member object.
519         *
520         * Returns @c true if this Member object is reflecting a "valid" member
521         * object. The default constructor creates Member objects initialized to be
522         * "invalid" Member objects by default. That way one can detect whether
523         * a Member object was ever assigned to something meaningful.
524         *
525         * Note that this class also implements the @c bool operator, both return
526         * the same boolean result value.
527         */
528      bool Member::isValid() const {      bool Member::isValid() const {
529          return m_uid && !m_name.empty() && m_type;          return m_uid && !m_name.empty() && m_type;
530      }      }
531    
532        /** @brief Comparison for equalness.
533         *
534         * Returns @c true if the two Member objects being compared can be
535         * considered to be "equal" C/C++ members. They are considered to be
536         * equal if their data type, member name, their offset within their parent
537         * containing C/C++ data structure, as well as their original native C/C++
538         * instance were exactly identical.
539         */
540      bool Member::operator==(const Member& other) const {      bool Member::operator==(const Member& other) const {
541          return m_uid    == other.m_uid &&          return m_uid    == other.m_uid &&
542                 m_offset == other.m_offset &&                 m_offset == other.m_offset &&
# Line 161  namespace Serialization { Line 544  namespace Serialization {
544                 m_type   == other.m_type;                 m_type   == other.m_type;
545      }      }
546    
547        /** @brief Comparison for inequalness.
548         *
549         * Returns the inverse result of what Member::operator==() would return.
550         * So refer to the latter for more details.
551         */
552      bool Member::operator!=(const Member& other) const {      bool Member::operator!=(const Member& other) const {
553          return !operator==(other);          return !operator==(other);
554      }      }
555    
556        /** @brief Smaller than comparison.
557         *
558         * Returns @c true if this Member object can be consider to be "smaller"
559         * than the @a other Member object being compared with. This operator
560         * is actually quite arbitrarily implemented and may change at any time,
561         * and thus result for the same member representations may change in
562         * future at any time.
563         *
564         * This operator is basically implemented for allowing this DataType class
565         * to be used with various standard template library (STL) classes, which
566         * require sorting operators to be implemented.
567         */
568      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
569          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
570                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
# Line 175  namespace Serialization { Line 575  namespace Serialization {
575                 m_type < other.m_type)));                 m_type < other.m_type)));
576      }      }
577    
578        /** @brief Greater than comparison.
579         *
580         * Returns @c true if this Member object can be consider to be "greater"
581         * than the @a other Member object being compared with. This operator
582         * is actually quite arbitrarily implemented and may change at any time,
583         * and thus result for the same member representations may change in
584         * future at any time.
585         *
586         * This operator is basically implemented for allowing this DataType class
587         * to be used with various standard template library (STL) classes, which
588         * require sorting operators to be implemented.
589         */
590      bool Member::operator>(const Member& other) const {      bool Member::operator>(const Member& other) const {
591          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
592      }      }
# Line 182  namespace Serialization { Line 594  namespace Serialization {
594      // *************** Object ***************      // *************** Object ***************
595      // *      // *
596    
597        /** @brief Default constructor (for an "invalid" Object).
598         *
599         * Initializes an Object instance as being an "invalid" Object.
600         * Thus calling isValid(), after creating an Object instance with this
601         * constructor, would return @c false.
602         *
603         * Usually you are not supposed to create (meaningful) Object instances on
604         * your own. They are typically constructed by the Archive class for you.
605         *
606         * @see Archive::rootObject(), Archive::objectByUID()
607         */
608      Object::Object() {      Object::Object() {
609          m_version = 0;          m_version = 0;
610          m_minVersion = 0;          m_minVersion = 0;
611      }      }
612    
613        /** @brief Constructor for a "meaningful" Object.
614         *
615         * Initializes a "meaningful" Object instance as being. Thus calling
616         * isValid(), after creating an Object instance with this constructor,
617         * should return @c true, provided that the arguments passed to this
618         * constructor construe a valid object representation.
619         *
620         * Usually you are not supposed to create (meaningful) Object instances on
621         * your own. They are typically constructed by the Archive class for you.
622         *
623         * @see Archive::rootObject(), Archive::objectByUID()
624         *
625         * @param uidChain - unique identifier chain of the object to be constructed
626         * @param type - C/C++ data type of the actual native object this abstract
627         *               Object instance should reflect after calling this
628         *               constructor
629         */
630      Object::Object(UIDChain uidChain, DataType type) {      Object::Object(UIDChain uidChain, DataType type) {
631          m_type = type;          m_type = type;
632          m_uid  = uidChain;          m_uid  = uidChain;
# Line 195  namespace Serialization { Line 635  namespace Serialization {
635          //m_data.resize(type.size());          //m_data.resize(type.size());
636      }      }
637    
638        /** @brief Check if this is a valid Object instance.
639         *
640         * Returns @c true if this Object instance is reflecting a "valid" Object.
641         * The default constructor creates Object instances initialized to be
642         * "invalid" Objects by default. That way one can detect whether an Object
643         * instance was ever assigned to something meaningful.
644         *
645         * Note that this class also implements the @c bool operator, both return
646         * the same boolean result value.
647         */
648      bool Object::isValid() const {      bool Object::isValid() const {
649          return m_type && !m_uid.empty();          return m_type && !m_uid.empty();
650      }      }
651    
652        /** @brief Unique identifier of this Object.
653         *
654         * Returns the unique identifier for the original native C/C++ data this
655         * abstract Object instance is reflecting. If this Object is representing
656         * a C/C++ pointer (of first degree) then @c uid() (or @c uid(0) ) returns
657         * the unique identifier of the pointer itself, whereas @c uid(1) returns
658         * the unique identifier of the original C/C++ data that pointer was
659         * actually pointing to.
660         *
661         * @see UIDChain for more details about this overall topic.
662         */
663        UID Object::uid(int index) const {
664            return (index < m_uid.size()) ? m_uid[index] : NO_UID;
665        }
666    
667        /** @brief Unique identifier chain of this Object.
668         *
669         * Returns the entire unique identifier chain of this Object.
670         *
671         * @see uid() and UIDChain for more details about this overall topic.
672         */
673        const UIDChain& Object::uidChain() const {
674            return m_uid;
675        }
676    
677        /** @brief C/C++ data type this Object is reflecting.
678         *
679         * Returns the precise original C/C++ data type of the original native
680         * C/C++ object or data this Object instance is reflecting.
681         */
682        const DataType& Object::type() const {
683            return m_type;
684        }
685    
686        /** @brief Raw data of the original native C/C++ data.
687         *
688         * Returns the raw data value of the original C/C++ data this Object is
689         * reflecting. So the precise raw data value, layout and size is dependent
690         * to the precise C/C++ data type of the original native C/C++ data. However
691         * potentially required endian correction is already automatically applied
692         * for you. That means you can safely, directly C-cast the raw data returned
693         * by this method to the respective native C/C++ data type in order to
694         * access and use the value for some purpose, at least if the respective
695         * data is of any fundamental, primitive C/C++ data type, or also to a
696         * certain extent if the type is user defined @c enum type.
697         *
698         * However directly C-casting this raw data for user defined @c struct or
699         * @c class types is not possible. For those user defined data structures
700         * this method always returns empty raw data instead.
701         *
702         * Note however that there are more convenient methods in the Archive class
703         * to get the right value for the individual data types instead.
704         *
705         * @see Archive::valueAsInt(), Archive::valueAsReal(), Archive::valueAsBool(),
706         *      Archive::valueAsString()
707         */
708        const RawData& Object::rawData() const {
709            return m_data;
710        }
711    
712        /** @brief Version of original user defined C/C++ @c struct or @c class.
713         *
714         * In case this Object is reflecting a native C/C++ @c struct or @c class
715         * type, then this method returns the version of that native C/C++ @c struct
716         * or @c class layout or implementation. For primitive, fundamental C/C++
717         * data types the return value of this method has no meaning.
718         *
719         * @see Archive::setVersion() for more details about this overall topic.
720         */
721        Version Object::version() const {
722            return m_version;
723        }
724    
725        /** @brief Minimum version of original user defined C/C++ @c struct or @c class.
726         *
727         * In case this Object is reflecting a native C/C++ @c struct or @c class
728         * type, then this method returns the "minimum" version of that native C/C++
729         * @c struct or @c class layout or implementation which it may be compatible
730         * with. For primitive, fundamental C/C++ data types the return value of
731         * this method has no meaning.
732         *
733         * @see Archive::setVersion() and Archive::setMinVersion() for more details
734         *      about this overall topic.
735         */
736        Version Object::minVersion() const {
737            return m_minVersion;
738        }
739    
740        /** @brief All members of the original native C/C++ @c struct or @c class instance.
741         *
742         * In case this Object is reflecting a native C/C++ @c struct or @c class
743         * type, then this method returns all member variables of that original
744         * native C/C++ @c struct or @c class instance. For primitive, fundamental
745         * C/C++ data types this method returns an empty vector instead.
746         *
747         * Example:
748         * @code
749         * struct Foo {
750         *     int  a;
751         *     bool b;
752         *     double someValue;
753         * };
754         * @endcode
755         * Considering above's C++ code, a serialized Object representation of such
756         * a native @c Foo class would have 3 members @c a, @c b and @c someValue.
757         *
758         * Note that the respective serialize() method implementation of that
759         * fictional C++ @c struct @c Foo actually defines which members are going
760         * to be serialized and deserialized for instances of class @c Foo. So in
761         * practice the members returned by method members() here might return a
762         * different set of members as actually defined in the original C/C++ struct
763         * header declaration.
764         *
765         * The precise sequence of the members returned by this method here depends
766         * on the actual serialize() implementation of the user defined C/C++
767         * @c struct or @c class.
768         *
769         * @see Object::sequenceIndexOf() for more details about the precise order
770         *      of members returned by this method in the same way.
771         */
772        std::vector<Member>& Object::members() {
773            return m_members;
774        }
775    
776        /** @brief All members of the original native C/C++ @c struct or @c class instance (read only).
777         *
778         * Returns the same result as overridden members() method above, it just
779         * returns a read-only result instead. See above's method description for
780         * details for the return value of this method instead.
781         */
782        const std::vector<Member>& Object::members() const {
783            return m_members;
784        }
785    
786        /** @brief Comparison for equalness.
787         *
788         * Returns @c true if the two Object instances being compared can be
789         * considered to be "equal" native C/C++ object instances. They are
790         * considered to be equal if they are representing the same original
791         * C/C++ data instance, which is essentially the case if the original
792         * reflecting native C/C++ data are sharing the same memory address and
793         * memory size (thus the exact same memory space) and originally had the
794         * exact same native C/C++ types.
795         */
796      bool Object::operator==(const Object& other) const {      bool Object::operator==(const Object& other) const {
797          // ignoring all other member variables here          // ignoring all other member variables here
798          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 206  namespace Serialization { Line 800  namespace Serialization {
800                 m_type == other.m_type;                 m_type == other.m_type;
801      }      }
802    
803        /** @brief Comparison for inequalness.
804         *
805         * Returns the inverse result of what Object::operator==() would return.
806         * So refer to the latter for more details.
807         */
808      bool Object::operator!=(const Object& other) const {      bool Object::operator!=(const Object& other) const {
809          return !operator==(other);          return !operator==(other);
810      }      }
811    
812        /** @brief Smaller than comparison.
813         *
814         * Returns @c true if this Object instance can be consider to be "smaller"
815         * than the @a other Object instance being compared with. This operator
816         * is actually quite arbitrarily implemented and may change at any time,
817         * and thus result for the same Object representations may change in future
818         * at any time.
819         *
820         * This operator is basically implemented for allowing this DataType class
821         * to be used with various standard template library (STL) classes, which
822         * require sorting operators to be implemented.
823         */
824      bool Object::operator<(const Object& other) const {      bool Object::operator<(const Object& other) const {
825          // ignoring all other member variables here          // ignoring all other member variables here
826          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 218  namespace Serialization { Line 829  namespace Serialization {
829                 m_type < other.m_type);                 m_type < other.m_type);
830      }      }
831    
832        /** @brief Greater than comparison.
833         *
834         * Returns @c true if this Object instance can be consider to be "greater"
835         * than the @a other Object instance being compared with. This operator
836         * is actually quite arbitrarily implemented and may change at any time,
837         * and thus result for the same Object representations may change in future
838         * at any time.
839         *
840         * This operator is basically implemented for allowing this DataType class
841         * to be used with various standard template library (STL) classes, which
842         * require sorting operators to be implemented.
843         */
844      bool Object::operator>(const Object& other) const {      bool Object::operator>(const Object& other) const {
845          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
846      }      }
847    
848        /** @brief Check version compatibility between Object instances.
849         *
850         * Use this method to check whether the two original C/C++ instances those
851         * two Objects are reflecting, were using a C/C++ data type which are version
852         * compatible with each other. By default all C/C++ Objects are considered
853         * to be version compatible. They might only be version incompatible if you
854         * enforced a certain backward compatibility constraint with your
855         * serialize() method implementation of your custom C/C++ @c struct or
856         * @c class types.
857         *
858         * You must only call this method on two Object instances which are
859         * representing the same data type, for example if both Objects reflect
860         * instances of the same user defined C++ class. Calling this method on
861         * completely different data types does not cause an error or exception, but
862         * its result would simply be useless for any purpose.
863         *
864         * @see Archive::setVersion() for more details about this overall topic.
865         */
866      bool Object::isVersionCompatibleTo(const Object& other) const {      bool Object::isVersionCompatibleTo(const Object& other) const {
867          if (this->version() == other.version())          if (this->version() == other.version())
868              return true;              return true;
# Line 231  namespace Serialization { Line 872  namespace Serialization {
872              return other.minVersion() <= this->version();              return other.minVersion() <= this->version();
873      }      }
874    
875        void Object::setVersion(Version v) {
876            m_version = v;
877        }
878    
879        void Object::setMinVersion(Version v) {
880            m_minVersion = v;
881        }
882    
883        /** @brief Get the member of this Object with given name.
884         *
885         * In case this Object is reflecting a native C/C++ @c struct or @c class
886         * type, then this method returns the abstract reflection of the requested
887         * member variable of the original native C/C++ @c struct or @c class
888         * instance. For primitive, fundamental C/C++ data types this method always
889         * returns an "invalid" Member instance instead.
890         *
891         * Example:
892         * @code
893         * struct Foo {
894         *     int  a;
895         *     bool b;
896         *     double someValue;
897         * };
898         * @endcode
899         * Consider that you serialized the native C/C++ @c struct as shown in this
900         * example, and assuming that you implemented the respective serialize()
901         * method of this C++ @c struct to serialize all its members, then you might
902         * call memberNamed("someValue") to get the details of the third member in
903         * this example for instance. In case the passed @a name is an unknown
904         * member name, then this method will return an "invalid" Member object
905         * instead.
906         *
907         * @param name - original name of the sought serialized member variable of
908         *               this Object reflection
909         * @returns abstract reflection of the sought member variable
910         * @see Member::isValid(), Object::members()
911         */
912      Member Object::memberNamed(String name) const {      Member Object::memberNamed(String name) const {
913          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
914              if (m_members[i].name() == name)              if (m_members[i].name() == name)
# Line 238  namespace Serialization { Line 916  namespace Serialization {
916          return Member();          return Member();
917      }      }
918    
919        /** @brief Get the member of this Object with given unique identifier.
920         *
921         * This method behaves similar like method memberNamed() described above,
922         * but instead of searching for a member variable by name, it searches for
923         * a member with an abstract unique identifier instead. For primitive,
924         * fundamental C/C++ data types, for invalid or unknown unique identifiers,
925         * and for members which are actually not member instances of the original
926         * C/C++ @c struct or @c class instance this Object is reflecting, this
927         * method returns an "invalid" Member instance instead.
928         *
929         * @param uid - unique identifier of the member variable being sought
930         * @returns abstract reflection of the sought member variable
931         * @see Member::isValid(), Object::members(), Object::memberNamed()
932         */
933      Member Object::memberByUID(const UID& uid) const {      Member Object::memberByUID(const UID& uid) const {
934          if (!uid) return Member();          if (!uid) return Member();
935          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
# Line 255  namespace Serialization { Line 947  namespace Serialization {
947          }          }
948      }      }
949    
950        /** @brief Get all members of this Object with given data type.
951         *
952         * In case this Object is reflecting a native C/C++ @c struct or @c class
953         * type, then this method returns all member variables of that original
954         * native C/C++ @c struct or @c class instance which are matching the given
955         * requested data @a type. If this Object is reflecting a primitive,
956         * fundamental data type, or if there are no members of this Object with the
957         * requested precise C/C++ data type, then this method returns an empty
958         * vector instead.
959         *
960         * @param type - the precise C/C++ data type of the sought member variables
961         *               of this Object
962         * @returns vector with abstract reflections of the sought member variables
963         * @see Object::members(), Object::memberNamed()
964         */
965      std::vector<Member> Object::membersOfType(const DataType& type) const {      std::vector<Member> Object::membersOfType(const DataType& type) const {
966          std::vector<Member> v;          std::vector<Member> v;
967          for (int i = 0; i < m_members.size(); ++i) {          for (int i = 0; i < m_members.size(); ++i) {
# Line 265  namespace Serialization { Line 972  namespace Serialization {
972          return v;          return v;
973      }      }
974    
975        /** @brief Serialization/deserialization sequence number of the requested member.
976         *
977         * Returns the precise serialization/deserialization sequence number of the
978         * requested @a member variable.
979         *
980         * Example:
981         * @code
982         * struct Foo {
983         *     int  a;
984         *     bool b;
985         *     double c;
986         *
987         *     void serialize(Serialization::Archive* archive);
988         * };
989         * @endcode
990         * Assuming the declaration of the user defined native C/C++ @c struct
991         * @c Foo above, and assuming the following implementation of serialize():
992         * @code
993         * #define SRLZ(member) \
994         *   archive->serializeMember(*this, member, #member);
995         *
996         * void Foo::serialize(Serialization::Archive* archive) {
997         *     SRLZ(c);
998         *     SRLZ(a);
999         *     SRLZ(b);
1000         * }
1001         * @endcode
1002         * then @c sequenceIndexOf(obj.memberNamed("a")) returns 1,
1003         * @c sequenceIndexOf(obj.memberNamed("b")) returns 2, and
1004         * @c sequenceIndexOf(obj.memberNamed("c")) returns 0.
1005         */
1006      int Object::sequenceIndexOf(const Member& member) const {      int Object::sequenceIndexOf(const Member& member) const {
1007          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
1008              if (m_members[i] == member)              if (m_members[i] == member)
# Line 275  namespace Serialization { Line 1013  namespace Serialization {
1013      // *************** Archive ***************      // *************** Archive ***************
1014      // *      // *
1015    
1016        /** @brief Create an "empty" archive.
1017         *
1018         * This default constructor creates an "empty" archive which you then
1019         * subsequently for example might fill with serialized data like:
1020         * @code
1021         * Archive a;
1022         * a.serialize(&myRootObject);
1023         * @endcode
1024         * Or:
1025         * @code
1026         * Archive a;
1027         * a << myRootObject;
1028         * @endcode
1029         * Or you might also subsequently assign an already existing non-empty
1030         * to this empty archive, which effectively clones the other
1031         * archive (deep copy) or call decode() later on to assign a previously
1032         * serialized raw data stream.
1033         */
1034      Archive::Archive() {      Archive::Archive() {
1035          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1036          m_root = NO_UID;          m_root = NO_UID;
# Line 282  namespace Serialization { Line 1038  namespace Serialization {
1038          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1039      }      }
1040    
1041        /** @brief Create and fill the archive with the given serialized raw data.
1042         *
1043         * This constructor decodes the given raw @a data and constructs a
1044         * (non-empty) Archive object according to that given serialized data
1045         * stream.
1046         *
1047         * After this constructor returned, you may then traverse the individual
1048         * objects by starting with accessing the rootObject() for example. Finally
1049         * you might call deserialize() to restore your native C++ objects with the
1050         * content of this archive.
1051         *
1052         * @param data - the previously serialized raw data stream to be decoded
1053         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1054         *         incompatible or corrupt data stream or format.
1055         */
1056      Archive::Archive(const RawData& data) {      Archive::Archive(const RawData& data) {
1057          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1058          m_root = NO_UID;          m_root = NO_UID;
# Line 290  namespace Serialization { Line 1061  namespace Serialization {
1061          decode(m_rawData);          decode(m_rawData);
1062      }      }
1063    
1064        /** @brief Create and fill the archive with the given serialized raw C-buffer data.
1065         *
1066         * This constructor essentially works like the constructor above, but just
1067         * uses another data type for the serialized raw data stream being passed to
1068         * this class.
1069         *
1070         * This constructor decodes the given raw @a data and constructs a
1071         * (non-empty) Archive object according to that given serialized data
1072         * stream.
1073         *
1074         * After this constructor returned, you may then traverse the individual
1075         * objects by starting with accessing the rootObject() for example. Finally
1076         * you might call deserialize() to restore your native C++ objects with the
1077         * content of this archive.
1078         *
1079         * @param data - the previously serialized raw data stream to be decoded
1080         * @param size - size of @a data in bytes
1081         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1082         *         incompatible or corrupt data stream or format.
1083         */
1084      Archive::Archive(const uint8_t* data, size_t size) {      Archive::Archive(const uint8_t* data, size_t size) {
1085          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1086          m_root = NO_UID;          m_root = NO_UID;
# Line 301  namespace Serialization { Line 1092  namespace Serialization {
1092      Archive::~Archive() {      Archive::~Archive() {
1093      }      }
1094    
1095        /** @brief Root C++ object of this archive.
1096         *
1097         * In case this is a non-empty Archive, then this method returns the so
1098         * called "root" C++ object. If this is an empty archive, then this method
1099         * returns an "invalid" Object instance instead.
1100         *
1101         * @see Archive::serialize() for more details about the "root" object concept.
1102         * @see Object for more details about the overall object reflection concept.
1103         * @returns reflection of the original native C++ root object
1104         */
1105      Object& Archive::rootObject() {      Object& Archive::rootObject() {
1106          return m_allObjects[m_root];          return m_allObjects[m_root];
1107      }      }
# Line 401  namespace Serialization { Line 1202  namespace Serialization {
1202          return s;          return s;
1203      }      }
1204    
1205        template<typename T>
1206        static T _primitiveObjectValueToNumber(const Object& obj) {
1207            T value = 0;
1208            const DataType& type = obj.type();
1209            const ID& id = obj.uid().id;
1210            void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1211            if (!obj.m_data.empty())
1212                assert(type.size() == obj.m_data.size());
1213            if (type.isPrimitive() && !type.isPointer()) {
1214                if (type.isInteger() || type.isEnum()) {
1215                    if (type.isSigned()) {
1216                        if (type.size() == 1)
1217                            value = (T)*(int8_t*)ptr;
1218                        else if (type.size() == 2)
1219                            value = (T)*(int16_t*)ptr;
1220                        else if (type.size() == 4)
1221                            value = (T)*(int32_t*)ptr;
1222                        else if (type.size() == 8)
1223                            value = (T)*(int64_t*)ptr;
1224                        else
1225                            assert(false /* unknown signed int type size */);
1226                    } else {
1227                        if (type.size() == 1)
1228                            value = (T)*(uint8_t*)ptr;
1229                        else if (type.size() == 2)
1230                            value = (T)*(uint16_t*)ptr;
1231                        else if (type.size() == 4)
1232                            value = (T)*(uint32_t*)ptr;
1233                        else if (type.size() == 8)
1234                            value = (T)*(uint64_t*)ptr;
1235                        else
1236                            assert(false /* unknown unsigned int type size */);
1237                    }
1238                } else if (type.isReal()) {
1239                    if (type.size() == sizeof(float))
1240                        value = (T)*(float*)ptr;
1241                    else if (type.size() == sizeof(double))
1242                        value = (T)*(double*)ptr;
1243                    else
1244                        assert(false /* unknown floating point type */);
1245                } else if (type.isBool()) {
1246                    value = (T)*(bool*)ptr;
1247                } else {
1248                    assert(false /* unknown primitive type */);
1249                }
1250            }
1251            return value;
1252        }
1253    
1254      static String _encodePrimitiveValue(const Object& obj) {      static String _encodePrimitiveValue(const Object& obj) {
1255          return _encodeBlob( _primitiveObjectValueToString(obj) );          return _encodeBlob( _primitiveObjectValueToString(obj) );
1256      }      }
# Line 460  namespace Serialization { Line 1310  namespace Serialization {
1310      };      };
1311    
1312      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1313          if (!bThrow && p >= end)          if (!bThrow && p >= end) {
1314              return (_Blob) { p, end };              const _Blob blob =  { p, end };
1315                return blob;
1316            }
1317          size_t sz = 0;          size_t sz = 0;
1318          for (; true; ++p) {          for (; true; ++p) {
1319              if (p >= end)              if (p >= end)
# Line 476  namespace Serialization { Line 1328  namespace Serialization {
1328          ++p;          ++p;
1329          if (p + sz > end)          if (p + sz > end)
1330              throw Exception("Decode Error: Premature end of blob");              throw Exception("Decode Error: Premature end of blob");
1331          return (_Blob) { p, p + sz };          const _Blob blob = { p, p + sz };
1332            return blob;
1333      }      }
1334    
1335      template<typename T_int>      template<typename T_int>
# Line 580  namespace Serialization { Line 1433  namespace Serialization {
1433          const ID id = (ID) _popIntBlob<size_t>(p, end);          const ID id = (ID) _popIntBlob<size_t>(p, end);
1434          const size_t size = _popIntBlob<size_t>(p, end);          const size_t size = _popIntBlob<size_t>(p, end);
1435    
1436          return (UID) { id, size };          const UID uid = { id, size };
1437            return uid;
1438      }      }
1439    
1440      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
# Line 739  namespace Serialization { Line 1593  namespace Serialization {
1593          m_timeModified = _popTimeBlob(p, end);          m_timeModified = _popTimeBlob(p, end);
1594      }      }
1595    
1596        /** @brief Fill this archive with the given serialized raw data.
1597         *
1598         * Calling this method will decode the given raw @a data and constructs a
1599         * (non-empty) Archive object according to that given serialized @a data
1600         * stream.
1601         *
1602         * After this method returned, you may then traverse the individual
1603         * objects by starting with accessing the rootObject() for example. Finally
1604         * you might call deserialize() to restore your native C++ objects with the
1605         * content of this archive.
1606         *
1607         * @param data - the previously serialized raw data stream to be decoded
1608         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1609         *         incompatible or corrupt data stream or format.
1610         */
1611      void Archive::decode(const RawData& data) {      void Archive::decode(const RawData& data) {
1612          m_rawData = data;          m_rawData = data;
1613          m_allObjects.clear();          m_allObjects.clear();
# Line 752  namespace Serialization { Line 1621  namespace Serialization {
1621          _popRootBlob(p, end);          _popRootBlob(p, end);
1622      }      }
1623    
1624        /** @brief Fill this archive with the given serialized raw C-buffer data.
1625         *
1626         * This method essentially works like the decode() method above, but just
1627         * uses another data type for the serialized raw data stream being passed to
1628         * this method.
1629         *
1630         * Calling this method will decode the given raw @a data and constructs a
1631         * (non-empty) Archive object according to that given serialized @a data
1632         * stream.
1633         *
1634         * After this method returned, you may then traverse the individual
1635         * objects by starting with accessing the rootObject() for example. Finally
1636         * you might call deserialize() to restore your native C++ objects with the
1637         * content of this archive.
1638         *
1639         * @param data - the previously serialized raw data stream to be decoded
1640         * @param size - size of @a data in bytes
1641         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1642         *         incompatible or corrupt data stream or format.
1643         */
1644      void Archive::decode(const uint8_t* data, size_t size) {      void Archive::decode(const uint8_t* data, size_t size) {
1645          RawData rawData;          RawData rawData;
1646          rawData.resize(size);          rawData.resize(size);
# Line 759  namespace Serialization { Line 1648  namespace Serialization {
1648          decode(rawData);          decode(rawData);
1649      }      }
1650    
1651        /** @brief Raw data stream of this archive content.
1652         *
1653         * Call this method to get a raw data stream for the current content of this
1654         * archive, which you may use to i.e. store on disk or send vie network to
1655         * another machine for deserializing there. This method only returns a
1656         * meaningful content if this is a non-empty archive, that is if you either
1657         * serialized with this Archive object or decoded a raw data stream to this
1658         * Archive object before. If this is an empty archive instead, then this
1659         * method simply returns an empty raw data stream (of size 0) instead.
1660         *
1661         * Note that whenever you call this method, the "modified" state of this
1662         * archive will be reset to @c false.
1663         *
1664         * @see isModified()
1665         */
1666      const RawData& Archive::rawData() {      const RawData& Archive::rawData() {
1667          if (m_isModified) encode();          if (m_isModified) encode();
1668          return m_rawData;          return m_rawData;
1669      }      }
1670    
1671        /** @brief Name of the encoding format used by this Archive class.
1672         *
1673         * This method returns the name of the encoding format used to encode
1674         * serialized raw data streams.
1675         */
1676      String Archive::rawDataFormat() const {      String Archive::rawDataFormat() const {
1677          return MAGIC_START;          return MAGIC_START;
1678      }      }
1679    
1680        /** @brief Whether this archive was modified.
1681         *
1682         * This method returns the current "modified" state of this archive. When
1683         * either decoding a previously serialized raw data stream or after
1684         * serializing native C++ objects to this archive the modified state will
1685         * initially be set to @c false. However whenever you are modifying the
1686         * abstract data model of this archive afterwards, for example by removing
1687         * objects from this archive by calling remove() or removeMember(), or by
1688         * altering object values for example by calling setIntValue(), then the
1689         * "modified" state of this archive will automatically be set to @c true.
1690         *
1691         * You can reset the "modified" state explicitly at any time, by calling
1692         * rawData().
1693         */
1694      bool Archive::isModified() const {      bool Archive::isModified() const {
1695          return m_isModified;          return m_isModified;
1696      }      }
1697    
1698        /** @brief Clear content of this archive.
1699         *
1700         * Drops the entire content of this archive and thus resets this archive
1701         * back to become an empty archive.
1702         */
1703      void Archive::clear() {      void Archive::clear() {
1704          m_allObjects.clear();          m_allObjects.clear();
1705          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
# Line 781  namespace Serialization { Line 1709  namespace Serialization {
1709          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1710      }      }
1711    
1712        /** @brief Optional name of this archive.
1713         *
1714         * Returns the optional name of this archive that you might have assigned
1715         * to this archive before by calling setName(). If you haven't assigned any
1716         * name to this archive before, then this method simply returns an empty
1717         * string instead.
1718         */
1719      String Archive::name() const {      String Archive::name() const {
1720          return m_name;          return m_name;
1721      }      }
1722    
1723        /** @brief Assign a name to this archive.
1724         *
1725         * You may optionally assign an arbitrary name to this archive. The name
1726         * will be stored along with the archive, that is it will encoded with the
1727         * resulting raw data stream, and accordingly it will be decoded from the
1728         * raw data stream later on.
1729         *
1730         * @param name - arbitrary new name for this archive
1731         */
1732      void Archive::setName(String name) {      void Archive::setName(String name) {
1733          if (m_name == name) return;          if (m_name == name) return;
1734          m_name = name;          m_name = name;
1735          m_isModified = true;          m_isModified = true;
1736      }      }
1737    
1738        /** @brief Optional comments for this archive.
1739         *
1740         * Returns the optional comments for this archive that you might have
1741         * assigned to this archive before by calling setComment(). If you haven't
1742         * assigned any comment to this archive before, then this method simply
1743         * returns an empty string instead.
1744         */
1745      String Archive::comment() const {      String Archive::comment() const {
1746          return m_comment;          return m_comment;
1747      }      }
1748    
1749        /** @brief Assign a comment to this archive.
1750         *
1751         * You may optionally assign arbitrary comments to this archive. The comment
1752         * will be stored along with the archive, that is it will encoded with the
1753         * resulting raw data stream, and accordingly it will be decoded from the
1754         * raw data stream later on.
1755         *
1756         * @param comment - arbitrary new comment for this archive
1757         */
1758      void Archive::setComment(String comment) {      void Archive::setComment(String comment) {
1759          if (m_comment == comment) return;          if (m_comment == comment) return;
1760          m_comment = comment;          m_comment = comment;
# Line 818  namespace Serialization { Line 1778  namespace Serialization {
1778          return *pTm;          return *pTm;
1779      }      }
1780    
1781        /** @brief Date and time when this archive was initially created.
1782         *
1783         * Returns a UTC time stamp (date and time) when this archive was initially
1784         * created.
1785         */
1786      time_t Archive::timeStampCreated() const {      time_t Archive::timeStampCreated() const {
1787          return m_timeCreated;          return m_timeCreated;
1788      }      }
1789    
1790        /** @brief Date and time when this archive was modified for the last time.
1791         *
1792         * Returns a UTC time stamp (date and time) when this archive was modified
1793         * for the last time.
1794         */
1795      time_t Archive::timeStampModified() const {      time_t Archive::timeStampModified() const {
1796          return m_timeModified;          return m_timeModified;
1797      }      }
1798    
1799        /** @brief Date and time when this archive was initially created.
1800         *
1801         * Returns a calendar time information representing the date and time when
1802         * this archive was initially created. The optional @a base parameter may
1803         * be used to define to which time zone the returned data and time shall be
1804         * related to.
1805         *
1806         * @param base - (optional) time zone the result shall relate to, by default
1807         *               UTC time (Greenwhich Mean Time) is assumed instead
1808         */
1809      tm Archive::dateTimeCreated(time_base_t base) const {      tm Archive::dateTimeCreated(time_base_t base) const {
1810          return _convertTimeStamp(m_timeCreated, base);          return _convertTimeStamp(m_timeCreated, base);
1811      }      }
1812    
1813        /** @brief Date and time when this archive was modified for the last time.
1814         *
1815         * Returns a calendar time information representing the date and time when
1816         * this archive has been modified for the last time. The optional @a base
1817         * parameter may be used to define to which time zone the returned date and
1818         * time shall be related to.
1819         *
1820         * @param base - (optional) time zone the result shall relate to, by default
1821         *               UTC time (Greenwhich Mean Time) is assumed instead
1822         */
1823      tm Archive::dateTimeModified(time_base_t base) const {      tm Archive::dateTimeModified(time_base_t base) const {
1824          return _convertTimeStamp(m_timeModified, base);          return _convertTimeStamp(m_timeModified, base);
1825      }      }
1826    
1827        /** @brief Remove a member variable from the given object.
1828         *
1829         * Removes the member variable @a member from its containing object
1830         * @a parent and sets the modified state of this archive to @c true.
1831         * If the given @a parent object does not contain the given @a member then
1832         * this method does nothing.
1833         *
1834         * This method provides a means of "partial" deserialization. By removing
1835         * either objects or members from this archive before calling deserialize(),
1836         * only the remaining objects and remaining members will be restored by this
1837         * framework, all other data of your C++ classes remain untouched.
1838         *
1839         * @param parent - Object which contains @a member
1840         * @param member - member to be removed
1841         * @see isModified() for details about the modified state.
1842         * @see Object for more details about the overall object reflection concept.
1843         */
1844      void Archive::removeMember(Object& parent, const Member& member) {      void Archive::removeMember(Object& parent, const Member& member) {
1845          parent.remove(member);          parent.remove(member);
1846          m_isModified = true;          m_isModified = true;
1847      }      }
1848    
1849        /** @brief Remove an object from this archive.
1850         *
1851         * Removes the object @obj from this archive and sets the modified state of
1852         * this archive to @c true. If the passed object is either invalid, or does
1853         * not exist in this archive, then this method does nothing.
1854         *
1855         * This method provides a means of "partial" deserialization. By removing
1856         * either objects or members from this archive before calling deserialize(),
1857         * only the remaining objects and remaining members will be restored by this
1858         * framework, all other data of your C++ classes remain untouched.
1859         *
1860         * @param obj - the object to be removed from this archive
1861         * @see isModified() for details about the modified state.
1862         * @see Object for more details about the overall object reflection concept.
1863         */
1864      void Archive::remove(const Object& obj) {      void Archive::remove(const Object& obj) {
1865          //FIXME: Should traverse from root object and remove all members associated with this object          //FIXME: Should traverse from root object and remove all members associated with this object
1866          if (!obj.uid()) return;          if (!obj.uid()) return;
# Line 846  namespace Serialization { Line 1868  namespace Serialization {
1868          m_isModified = true;          m_isModified = true;
1869      }      }
1870    
1871        /** @brief Access object by its unique identifier.
1872         *
1873         * Returns the object of this archive with the given unique identifier
1874         * @a uid. If the given @a uid is invalid, or if this archive does not
1875         * contain an object with the given unique identifier, then this method
1876         * returns an invalid object instead.
1877         *
1878         * @param uid - unique identifier of sought object
1879         * @see Object for more details about the overall object reflection concept.
1880         * @see Object::isValid() for valid/invalid objects
1881         */
1882      Object& Archive::objectByUID(const UID& uid) {      Object& Archive::objectByUID(const UID& uid) {
1883          return m_allObjects[uid];          return m_allObjects[uid];
1884      }      }
1885    
1886        /** @brief Set the current version for the given object.
1887         *
1888         * Essentially behaves like above's setVersion() method, it just uses the
1889         * abstract reflection data type instead for the respective @a object being
1890         * passed to this method. Refer to above's setVersion() documentation about
1891         * the precise behavior details of setVersion().
1892         *
1893         * @param object - object to set the current version for
1894         * @param v - new current version to set for @a object
1895         */
1896        void Archive::setVersion(Object& object, Version v) {
1897            if (!object) return;
1898            object.setVersion(v);
1899            m_isModified = true;
1900        }
1901    
1902        /** @brief Set the minimum version for the given object.
1903         *
1904         * Essentially behaves like above's setMinVersion() method, it just uses the
1905         * abstract reflection data type instead for the respective @a object being
1906         * passed to this method. Refer to above's setMinVersion() documentation
1907         * about the precise behavior details of setMinVersion().
1908         *
1909         * @param object - object to set the minimum version for
1910         * @param v - new minimum version to set for @a object
1911         */
1912        void Archive::setMinVersion(Object& object, Version v) {
1913            if (!object) return;
1914            object.setMinVersion(v);
1915            m_isModified = true;
1916        }
1917    
1918        /** @brief Set new value for given @c enum object.
1919         *
1920         * Sets the new @a value to the given @c enum @a object.
1921         *
1922         * @param object - the @c enum object to be changed
1923         * @param value - the new value to be assigned to the @a object
1924         * @throws Exception if @a object is not an @c enum type.
1925         */
1926      void Archive::setEnumValue(Object& object, uint64_t value) {      void Archive::setEnumValue(Object& object, uint64_t value) {
1927          if (!object) return;          if (!object) return;
1928          if (!object.type().isEnum())          if (!object.type().isEnum())
# Line 882  namespace Serialization { Line 1955  namespace Serialization {
1955          m_isModified = true;          m_isModified = true;
1956      }      }
1957    
1958        /** @brief Set new integer value for given integer object.
1959         *
1960         * Sets the new integer @a value to the given integer @a object. Currently
1961         * this framework handles any integer data type up to 64 bit. For larger
1962         * integer types an assertion failure will be raised.
1963         *
1964         * @param object - the integer object to be changed
1965         * @param value - the new value to be assigned to the @a object
1966         * @throws Exception if @a object is not an integer type.
1967         */
1968      void Archive::setIntValue(Object& object, int64_t value) {      void Archive::setIntValue(Object& object, int64_t value) {
1969          if (!object) return;          if (!object) return;
1970          if (!object.type().isInteger())          if (!object.type().isInteger())
# Line 921  namespace Serialization { Line 2004  namespace Serialization {
2004          m_isModified = true;          m_isModified = true;
2005      }      }
2006    
2007        /** @brief Set new floating point value for given floating point object.
2008         *
2009         * Sets the new floating point @a value to the given floating point
2010         * @a object. Currently this framework supports single precision @c float
2011         * and double precision @c double floating point data types. For all other
2012         * floating point types this method will raise an assertion failure.
2013         *
2014         * @param object - the floating point object to be changed
2015         * @param value - the new value to be assigned to the @a object
2016         * @throws Exception if @a object is not a floating point based type.
2017         */
2018      void Archive::setRealValue(Object& object, double value) {      void Archive::setRealValue(Object& object, double value) {
2019          if (!object) return;          if (!object) return;
2020          if (!object.type().isReal())          if (!object.type().isReal())
# Line 943  namespace Serialization { Line 2037  namespace Serialization {
2037          m_isModified = true;          m_isModified = true;
2038      }      }
2039    
2040        /** @brief Set new boolean value for given boolean object.
2041         *
2042         * Sets the new boolean @a value to the given boolean @a object.
2043         *
2044         * @param object - the boolean object to be changed
2045         * @param value - the new value to be assigned to the @a object
2046         * @throws Exception if @a object is not a boolean type.
2047         */
2048      void Archive::setBoolValue(Object& object, bool value) {      void Archive::setBoolValue(Object& object, bool value) {
2049          if (!object) return;          if (!object) return;
2050          if (!object.type().isBool())          if (!object.type().isBool())
# Line 960  namespace Serialization { Line 2062  namespace Serialization {
2062          m_isModified = true;          m_isModified = true;
2063      }      }
2064    
2065        /** @brief Automatically cast and assign appropriate value to object.
2066         *
2067         * This method automatically converts the given @a value from textual string
2068         * representation into the appropriate data format of the requested
2069         * @a object. So this method is a convenient way to change values of objects
2070         * in this archive with your applications in automated way, i.e. for
2071         * implementing an editor where the user is able to edit values of objects
2072         * in this archive by entering the values as text with a keyboard.
2073         *
2074         * @throws Exception if the passed @a object is not a fundamental, primitive
2075         *         data type or if the provided textual value cannot be converted
2076         *         into an appropriate value for the requested object.
2077         */
2078      void Archive::setAutoValue(Object& object, String value) {      void Archive::setAutoValue(Object& object, String value) {
2079          if (!object) return;          if (!object) return;
2080          const DataType& type = object.type();          const DataType& type = object.type();
# Line 967  namespace Serialization { Line 2082  namespace Serialization {
2082              setIntValue(object, atoll(value.c_str()));              setIntValue(object, atoll(value.c_str()));
2083          else if (type.isReal())          else if (type.isReal())
2084              setRealValue(object, atof(value.c_str()));              setRealValue(object, atof(value.c_str()));
2085          else if (type.isBool())          else if (type.isBool()) {
2086              setBoolValue(object, atof(value.c_str()));              String val = toLowerCase(value);
2087          else if (type.isEnum())              if (val == "true" || val == "yes" || val == "1")
2088                    setBoolValue(object, true);
2089                else if (val == "false" || val == "no" || val == "0")
2090                    setBoolValue(object, false);
2091                else
2092                    setBoolValue(object, atof(value.c_str()));
2093            } else if (type.isEnum())
2094              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2095          else          else
2096              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
2097      }      }
2098    
2099        /** @brief Get value of object as string.
2100         *
2101         * Converts the current value of the given @a object into a textual string
2102         * and returns that string.
2103         *
2104         * @param object - object whose value shall be retrieved
2105         * @throws Exception if the given object is either invalid, or if the object
2106         *         is not a fundamental, primitive data type.
2107         */
2108      String Archive::valueAsString(const Object& object) {      String Archive::valueAsString(const Object& object) {
2109          if (!object)          if (!object)
2110              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 989  namespace Serialization { Line 2119  namespace Serialization {
2119          return _primitiveObjectValueToString(*pObject);          return _primitiveObjectValueToString(*pObject);
2120      }      }
2121    
2122        /** @brief Get integer value of object.
2123         *
2124         * Returns the current integer value of the requested integer @a object or
2125         * @c enum object.
2126         *
2127         * @param object - object whose value shall be retrieved
2128         * @throws Exception if the given object is either invalid, or if the object
2129         *         is neither an integer nor @c enum data type.
2130         */
2131        int64_t Archive::valueAsInt(const Object& object) {
2132            if (!object)
2133                throw Exception("Invalid object");
2134            if (!object.type().isInteger() && !object.type().isEnum())
2135                throw Exception("Object is neither an integer nor an enum");
2136            const Object* pObject = &object;
2137            if (object.type().isPointer()) {
2138                const Object& obj = objectByUID(object.uid(1));
2139                if (!obj) return 0;
2140                pObject = &obj;
2141            }
2142            return _primitiveObjectValueToNumber<int64_t>(*pObject);
2143        }
2144    
2145        /** @brief Get floating point value of object.
2146         *
2147         * Returns the current floating point value of the requested floating point
2148         * @a object.
2149         *
2150         * @param object - object whose value shall be retrieved
2151         * @throws Exception if the given object is either invalid, or if the object
2152         *         is not a floating point based type.
2153         */
2154        double Archive::valueAsReal(const Object& object) {
2155            if (!object)
2156                throw Exception("Invalid object");
2157            if (!object.type().isReal())
2158                throw Exception("Object is not an real type");
2159            const Object* pObject = &object;
2160            if (object.type().isPointer()) {
2161                const Object& obj = objectByUID(object.uid(1));
2162                if (!obj) return 0;
2163                pObject = &obj;
2164            }
2165            return _primitiveObjectValueToNumber<double>(*pObject);
2166        }
2167    
2168        /** @brief Get boolean value of object.
2169         *
2170         * Returns the current boolean value of the requested boolean @a object.
2171         *
2172         * @param object - object whose value shall be retrieved
2173         * @throws Exception if the given object is either invalid, or if the object
2174         *         is not a boolean data type.
2175         */
2176        bool Archive::valueAsBool(const Object& object) {
2177            if (!object)
2178                throw Exception("Invalid object");
2179            if (!object.type().isBool())
2180                throw Exception("Object is not a bool");
2181            const Object* pObject = &object;
2182            if (object.type().isPointer()) {
2183                const Object& obj = objectByUID(object.uid(1));
2184                if (!obj) return 0;
2185                pObject = &obj;
2186            }
2187            return _primitiveObjectValueToNumber<bool>(*pObject);
2188        }
2189    
2190      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2191      // *      // *
2192    
# Line 1088  namespace Serialization { Line 2286  namespace Serialization {
2286      // *************** Exception ***************      // *************** Exception ***************
2287      // *      // *
2288    
2289        /** @brief Print exception message to stdout.
2290         *
2291         * Prints the message of this Exception to the currently defined standard
2292         * output (that is to the terminal console for example).
2293         */
2294      void Exception::PrintMessage() {      void Exception::PrintMessage() {
2295          std::cout << "Serialization::Exception: " << Message << std::endl;          std::cout << "Serialization::Exception: " << Message << std::endl;
2296      }      }

Legend:
Removed from v.3159  
changed lines
  Added in v.3186

  ViewVC Help
Powered by ViewVC