/[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 3774 by schoenebeck, Tue May 19 14:55:48 2020 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2017 Christian Schoenebeck                              *   *   Copyright (C) 2017-2020 Christian Schoenebeck                         *
4   *                      <cuse@users.sourceforge.net>                       *   *                           <cuse@users.sourceforge.net>                  *
5   *                                                                         *   *                                                                         *
6   *   This library is part of libgig.                                       *   *   This library is part of libgig.                                       *
7   *                                                                         *   *                                                                         *
# Line 21  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    // enable implementation specific declarations in Serialization.h required to
25    // build this C++ unit, which should be ignored in the public API though
26    #define LIBGIG_SERIALIZATION_INTERNAL 1
27    
28  #include "Serialization.h"  #include "Serialization.h"
29    
30  #include <iostream>  #include <iostream>
 #include <assert.h>  
31  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
32  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
33    #ifdef _MSC_VER
34    # include <windows.h>
35    # include <dbghelp.h>
36    #else
37    # include <cxxabi.h>
38    #endif
39  #include "helper.h"  #include "helper.h"
40    
41    #define LIBGIG_EPOCH_TIME ((time_t)0)
42    
43  namespace Serialization {  namespace Serialization {
44    
45      // *************** DataType ***************      // *************** DataType ***************
46      // *      // *
47    
48      static UID _createNullUID() {      static UID _createNullUID() {
49          return (UID) { NULL, 0 };          const UID uid = { NULL, 0 };
50            return uid;
51      }      }
52    
53      const UID NO_UID = _createNullUID();      const UID NO_UID = _createNullUID();
54    
55        /** @brief Check whether this is a valid unique identifier.
56         *
57         * Returns @c false if this UID can be considered an invalid unique
58         * identifier. This is for example the case if this UID object was not
59         * explicitly set to some certain meaningful unique identifier value, or if
60         * this UID object was intentionally assigned the constant @c NO_UID value.
61         * Both represent essentially an UID object which is all zero.
62         *
63         * Note that this class also implements the @c bool operator, both return
64         * the same boolean result.
65         */
66      bool UID::isValid() const {      bool UID::isValid() const {
67          return id != NULL && id != (void*)-1 && size;          return id != NULL && id != (void*)-1 && size;
68      }      }
# Line 48  namespace Serialization { Line 70  namespace Serialization {
70      // *************** DataType ***************      // *************** DataType ***************
71      // *      // *
72    
73        /** @brief Default constructor (as "invalid" DataType).
74         *
75         * Initializes a DataType object as being an "invalid" DataType object.
76         * Thus calling isValid(), after creating a DataType object with this
77         * constructor, would return @c false.
78         *
79         * To create a valid and meaningful DataType object instead, call the static
80         * function DataType::dataTypeOf() instead.
81         */
82      DataType::DataType() {      DataType::DataType() {
83          m_size = 0;          m_size = 0;
84          m_isPointer = false;          m_isPointer = false;
85      }      }
86    
87        /** @brief Constructs a valid DataType object.
88         *
89         * Initializes this object as "valid" DataType object, with specific and
90         * useful data type information.
91         *
92         * This is a protected constructor which should not be called directly by
93         * applications, as its argument list is somewhat implementation specific
94         * and might change at any time. Applications should call the static
95         * function DataType::dataTypeOf() instead.
96         *
97         * @param isPointer - whether pointer type (i.e. a simple memory address)
98         * @param size - native size of data type in bytes (i.e. according to
99         *               @c sizeof() C/C++ keyword)
100         * @param baseType - this framework's internal name for specifying the base
101         *                   type in a coarse way, which must be either one of:
102         *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",
103         *                   "int64", "uint64", "bool", "real32", "real64",
104         *                   "String", "enum", "union" or "class"
105         * @param customType - this is only used for base types "enum", "union" or
106         *                     "class", in which case this identifies the user
107         *                     defined type name (e.g. "Foo" for @c class @c Foo ),
108         *                     for all other types this is empty
109         */
110      DataType::DataType(bool isPointer, int size, String baseType, String customType) {      DataType::DataType(bool isPointer, int size, String baseType, String customType) {
111          m_size = size;          m_size = size;
112          m_isPointer = isPointer;          m_isPointer = isPointer;
# Line 60  namespace Serialization { Line 114  namespace Serialization {
114          m_customTypeName = customType;          m_customTypeName = customType;
115      }      }
116    
117        /** @brief Check if this is a valid DataType object.
118         *
119         * Returns @c true if this DataType object is reflecting a valid data type.
120         * The default constructor creates DataType objects initialized to be
121         * "invalid" DataType objects by default. That way one can detect whether
122         * a DataType object was ever assigned to something meaningful.
123         *
124         * Note that this class also implements the @c bool operator, both return
125         * the same boolean result.
126         */
127      bool DataType::isValid() const {      bool DataType::isValid() const {
128          return m_size;          return m_size;
129      }      }
130    
131        /** @brief Whether this is reflecting a C/C++ pointer type.
132         *
133         * Returns @true if the respective native C/C++ object, member or variable
134         * (this DataType instance is reflecting) is a C/C++ pointer type.
135         */
136      bool DataType::isPointer() const {      bool DataType::isPointer() const {
137          return m_isPointer;          return m_isPointer;
138      }      }
139    
140        /** @brief Whether this is reflecting a C/C++ @c struct or @c class type.
141         *
142         * Returns @c true if the respective native C/C++ object, member or variable
143         * (this DataType instance is reflecting) is a C/C++ @c struct or @c class
144         * type, with one exception: @c String objects are handled by this framework
145         * as if they were a primitive type.
146         *
147         * Note that in the following example:
148         * @code
149         * struct Foo {
150         *     int  a;
151         *     bool b;
152         * };
153         * Foo foo;
154         * Foo* pFoo;
155         * @endcode
156         * the DataType objects of both @c foo, as well as of the C/C++ pointer
157         * @c pFoo would both return @c true for isClass() here!
158         *
159         * @see isPointer()
160         */
161      bool DataType::isClass() const {      bool DataType::isClass() const {
162          return m_baseTypeName == "class";          return m_baseTypeName == "class";
163      }      }
164    
165        /** @brief Whether this is reflecting a fundamental C/C++ data type.
166         *
167         * Returns @c true if the respective native C/C++ object, member or variable
168         * (this DataType instance is reflecting) is a primitive, fundamental C/C++
169         * data type. Those are fundamental data types which are already predefined
170         * by the C/C++ language, for example: @c char, @c int, @c float, @c double,
171         * @c bool, but also @c String objects and @b any pointer types like
172         * @c int*, @c double**, but including pointers to user defined types like:
173         * @code
174         * struct Foo {
175         *     int  a;
176         *     bool b;
177         * };
178         * Foo* pFoo;
179         * @endcode
180         * So the DataType object of @c pFoo in the latter example would also return
181         * @c true for isPrimitive() here!
182         *
183         * @see isPointer()
184         */
185      bool DataType::isPrimitive() const {      bool DataType::isPrimitive() const {
186          return !isClass();          return !isClass();
187      }      }
188    
189        /** @brief Whether this is a C++ @c String data type.
190         *
191         * Returns @c true if the respective native C/C++ object, member or variable
192         * (this DataType instance is reflecting) is a C++ @c String object (a.k.a.
193         * @c std::string from the C++ STL).
194         *
195         * Note that this framework handles @c String objects as if they were a
196         * fundamental, primitive C/C++ data type, so @c isPrimitive() returns
197         * @c true for strings.
198         */
199        bool DataType::isString() const {
200            return m_baseTypeName == "String";
201        }
202    
203        /** @brief Whether this is an integer C/C++ data type.
204         *
205         * Returns @c true if the respective native C/C++ object, member or variable
206         * (this DataType instance is reflecting) is a (fundamental, primitive)
207         * integer data type. So these are all @c int and @c unsigned @c int types
208         * of any size. It does not include floating point ("real") types though.
209         *
210         * You may use isSigned() to further check whether this data type allows
211         * negative numbers.
212         *
213         * Note that this method also returns @c true on integer pointer types!
214         *
215         * @see isPointer()
216         */
217      bool DataType::isInteger() const {      bool DataType::isInteger() const {
218          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
219                 m_baseTypeName.substr(0, 4) == "uint";                 m_baseTypeName.substr(0, 4) == "uint";
220      }      }
221    
222        /** @brief Whether this is a floating point based C/C++ data type.
223         *
224         * Returns @c true if the respective native C/C++ object, member or variable
225         * (this DataType instance is reflecting) is a (fundamental, primitive)
226         * floating point based data type. So these are currently the C/C++ @c float
227         * and @c double types. It does not include integer types though.
228         *
229         * Note that this method also returns @c true on @c float pointer and
230         * @c double pointer types!
231         *
232         * @see isPointer()
233         */
234      bool DataType::isReal() const {      bool DataType::isReal() const {
235          return m_baseTypeName.substr(0, 4) == "real";          return m_baseTypeName.substr(0, 4) == "real";
236      }      }
237    
238        /** @brief Whether this is a boolean C/C++ data type.
239         *
240         * Returns @c true if the respective native C/C++ object, member or variable
241         * (this DataType instance is reflecting) is a (fundamental, primitive)
242         * boolean data type. So this is the case for the C++ @c bool data type.
243         * It does not include integer or floating point types though.
244         *
245         * Note that this method also returns @c true on @c bool pointer types!
246         *
247         * @see isPointer()
248         */
249      bool DataType::isBool() const {      bool DataType::isBool() const {
250          return m_baseTypeName == "bool";          return m_baseTypeName == "bool";
251      }      }
252    
253        /** @brief Whether this is a C/C++ @c enum data type.
254         *
255         * Returns @c true if the respective native C/C++ object, member or variable
256         * (this DataType instance is reflecting) is a user defined enumeration
257         * data type. So this is the case for all C/C++ @c enum data types.
258         * It does not include integer (or even floating point) types though.
259         *
260         * Note that this method also returns @c true on @c enum pointer types!
261         *
262         * @see isPointer()
263         */
264      bool DataType::isEnum() const {      bool DataType::isEnum() const {
265          return m_baseTypeName == "enum";          return m_baseTypeName == "enum";
266      }      }
267    
268        /** @brief Whether this is a signed integer C/C++ data type.
269         *
270         * Returns @c true if the respective native C/C++ object, member or variable
271         * (this DataType instance is reflecting) is a (fundamental, primitive)
272         * signed integer data type. This is the case for are all @c unsigned
273         * @c int C/C++ types of any size. For all floating point ("real") based
274         * types this method returns @c false though!
275         *
276         * Note that this method also returns @c true on signed integer pointer
277         * types!
278         *
279         * @see isInteger();
280         */
281      bool DataType::isSigned() const {      bool DataType::isSigned() const {
282          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
283                 isReal();                 isReal();
284      }      }
285    
286        /** @brief Comparison for equalness.
287         *
288         * Returns @c true if the two DataType objects being compared can be
289         * considered to be "equal" C/C++ data types. They are considered to be
290         * equal if their underlying C/C++ data types are exactly identical. For
291         * example comparing @c int and @c unsigned int data types are considere to
292         * be @b not equal, since they are differently signed. Furthermore @c short
293         * @c int and @c long @c int would also not be considered to be equal, since
294         * they do have a different memory size. Additionally pointer type
295         * characteristic is compared as well. So a @c double type and @c double*
296         * type are also considered to be not equal data types and hence this method
297         * would return @c false.
298         *
299         * As an exception here, classes and structs with the same class/struct name
300         * but different sizes are also considered to be "equal". This relaxed
301         * requirement is necessary to retain backward compatiblity to older
302         * versions of the same native C++ classes/structs.
303         */
304      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
305          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
306                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
307                 m_size           == other.m_size &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
308                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
309      }      }
310    
311        /** @brief Comparison for inequalness.
312         *
313         * Returns the inverse result of what DataType::operator==() would return.
314         * So refer to the latter for more details.
315         */
316      bool DataType::operator!=(const DataType& other) const {      bool DataType::operator!=(const DataType& other) const {
317          return !operator==(other);          return !operator==(other);
318      }      }
319    
320        /** @brief Smaller than comparison.
321         *
322         * Returns @c true if this DataType object can be consider to be "smaller"
323         * than the @a other DataType object being compared with. This operator
324         * is actually quite arbitrarily implemented and may change at any time,
325         * and thus result for the same data types may change in future at any time.
326         *
327         * This operator is basically implemented for allowing this DataType class
328         * to be used with various standard template library (STL) classes, which
329         * require sorting operators to be implemented.
330         */
331      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
332          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
333                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
334                 m_customTypeName  < other.m_customTypeName ||                (m_customTypeName  < other.m_customTypeName ||
335                (m_customTypeName == other.m_customTypeName &&                (m_customTypeName == other.m_customTypeName &&
336                 m_size  < other.m_size ||                (m_size  < other.m_size ||
337                (m_size == other.m_size &&                (m_size == other.m_size &&
338                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)))));
339      }      }
340    
341        /** @brief Greater than comparison.
342         *
343         * Returns @c true if this DataType object can be consider to be "greater"
344         * than the @a other DataType object being compared with. This operator
345         * is actually quite arbitrarily implemented and may change at any time,
346         * and thus result for the same data types may change in future at any time.
347         *
348         * This operator is basically implemented for allowing this DataType class
349         * to be used with various standard template library (STL) classes, which
350         * require sorting operators to be implemented.
351         */
352      bool DataType::operator>(const DataType& other) const {      bool DataType::operator>(const DataType& other) const {
353          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
354      }      }
355    
356        /** @brief Human readable long description for this data type.
357         *
358         * Returns a human readable long description for this data type, designed
359         * for the purpose for being displayed to the user. Note that the
360         * implementation for this method and thus the precise textual strings
361         * returned by this method, may change at any time. So you should not rely
362         * on precise strings for certain data types, and you should not use the
363         * return values of this method for comparing data types with each other.
364         *
365         * This class implements various comparison operators, so you should use
366         * them for comparing DataTypes objects instead.
367         *
368         * @see baseTypeName(), customTypeName()
369         */
370      String DataType::asLongDescr() const {      String DataType::asLongDescr() const {
         //TODO: Demangling of C++ raw type names  
371          String s = m_baseTypeName;          String s = m_baseTypeName;
372          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
373              s += " " + m_customTypeName;              s += " " + customTypeName(true);
374          if (isPointer())          if (isPointer())
375              s += " pointer";              s += " pointer";
376          return s;          return s;
377      }      }
378    
379        /** @brief The base type name of this data type.
380         *
381         * Returns a textual short string identifying the basic type of name of this
382         * data type. For example for a 32 bit signed integer data type this method
383         * would return @c "int32". For all user defined C/C++ @c enum types this
384         * method would return "enum". For all user defined C/C++ @c struct @b and
385         * @c class types this method would return "class" for both. Note that the
386         * precise user defined type name (of i.e. @c enum, @c struct and @c class
387         * types) is not included in the string returned by this method, use
388         * customTypeName() to retrieve that information instead.
389         *
390         * The precise textual strings returned by this method are guaranteed to
391         * retain equal with future versions of this framework. So you can rely on
392         * them for using the return values of this method for comparison tasks in
393         * your application. Note however that this class also implements various
394         * comparison operators.
395         *
396         * Further it is important to know that this method returns the same string
397         * for pointers and non-pointers of the same underlying data type. So in the
398         * following example:
399         * @code
400         * #include <stdint.h>
401         * uint64_t i;
402         * uint64_t* pi;
403         * @endcode
404         * this method would return for both @c i and @c pi the string @c "uint64" !
405         *
406         * @see isPointer(), customTypeName()
407         */
408        String DataType::baseTypeName() const {
409            return m_baseTypeName;
410        }
411    
412        /** @brief The user defined C/C++ data type name of this data type.
413         *
414         * Call this method on user defined C/C++ data types like @c enum, @c struct
415         * and @c class types to retrieve the user defined type name portion of
416         * those data types. Note that this method is only intended for such user
417         * defined data types. For all fundamental, primitive data types (like i.e.
418         * @c int) this method returns an empty string instead.
419         *
420         * This method takes an optional boolean argument @b demangle, which allows
421         * you define whether you are interested in the raw C++ type name or rather
422         * the demangled custom type name. By default this method returns the raw
423         * C++ type name. The raw C++ type name is the one that is actually used
424         * in the compiled binaries and should be preferred for comparions tasks.
425         * The demangled C++ type name is a human readable representation of the
426         * type name instead, which you may use for displaying the user defined type
427         * name portion to the user, however you should not use the demangled
428         * representation for comparison tasks.
429         *
430         * Note that in the following example:
431         * @code
432         * struct Foo {
433         *     int  a;
434         *     bool b;
435         * };
436         * Foo foo;
437         * Foo* pFoo;
438         * @endcode
439         * this method would return the same string for both @c foo and @c pFoo !
440         * In the latter example @c customTypeName(true) would return for both
441         * @c foo and @c pFoo the string @c "Foo" as return value of this method.
442         *
443         * @b Windows: please note that the current implementation of this method
444         * on Windows is @b not thread safe!
445         *
446         * @see isPointer(), baseTypeName()
447         */
448        String DataType::customTypeName(bool demangle) const {
449            if (!demangle) return m_customTypeName;
450    #ifdef _MSC_VER
451            const size_t MAXLENGTH = 1024;
452            char result[MAXLENGTH];
453    
454            //FIXME: calling UnDecorateSymbolName() is not thread safe!
455            //Skip the first char
456            size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
457            if (size)
458            {
459                return result;
460            }
461            return m_customTypeName;
462    #else
463            int status;
464            char* result =
465                abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
466            String sResult = result;
467            free(result);
468            return (status == 0) ? sResult : m_customTypeName;
469    #endif
470        }
471    
472      // *************** Member ***************      // *************** Member ***************
473      // *      // *
474    
475        /** @brief Default constructor.
476         *
477         * Initializes a Member object as being an "invalid" Member object.
478         * Thus calling isValid(), after creating a Member object with this
479         * constructor, would return @c false.
480         *
481         * You are currently not supposed to create (meaningful) Member objects on
482         * your own. This framework automatically create such Member objects for
483         * you instead.
484         *
485         * @see Object::members()
486         */
487      Member::Member() {      Member::Member() {
488          m_uid = NO_UID;          m_uid = NO_UID;
489          m_offset = 0;          m_offset = 0;
# Line 148  namespace Serialization { Line 496  namespace Serialization {
496          m_type = type;          m_type = type;
497      }      }
498    
499        /** @brief Unique identifier of this member instance.
500         *
501         * Returns the unique identifier of the original C/C++ member instance of
502         * your C++ class. It is important to know that this unique identifier is
503         * not meant to be unique for Member instances themselves, but it is rather
504         * meant to be unique for the original native C/C++ data these Member
505         * instances are representing. So that means no matter how many individual
506         * Member objects are created, as long as they are representing the same
507         * original native member variable of the same original native
508         * instance of your C++ class, then all those separately created Member
509         * objects return the same unique identifier here.
510         *
511         * @see UID for more details
512         */
513        UID Member::uid() const {
514            return m_uid;
515        }
516    
517        /** @brief Name of the member.
518         *
519         * Returns the name of the native C/C++ member variable as originally typed
520         * in its C++ source code. So in the following example:
521         * @code
522         * struct Foo {
523         *     int  a;
524         *     bool b;
525         *     double someValue;
526         * };
527         * @endcode
528         * this method would usually return @c "a" for the first member of object
529         * instances of your native C/C++ @c struct @c Foo, and this method would
530         * usually return @c "someValue" for its third member.
531         *
532         * Note that when you implement the @c serialize() method of your own C/C++
533         * clases or strucs, you are able to override defining the precise name of
534         * your members. In that case this method would of course return the member
535         * names as explicitly forced by you instead.
536         */
537        String Member::name() const {
538            return m_name;
539        }
540    
541        /** @brief Offset of member in its containing parent data structure.
542         *
543         * Returns the offset of this member (in bytes) within its containing parent
544         * user defined data structure or class. So in the following example:
545         * @code
546         * #include <stdint.h>
547         * struct Foo __attribute__ ((__packed__)) {
548         *     int32_t a;
549         *     bool b;
550         *     double c;
551         * };
552         * @endcode
553         * this method would typically return @c 0 for member @c a, @c 4 for member
554         * @c b and @c 5 for member @c c. As you have noted in the latter example,
555         * the structure @c Foo was declared to have "packed" data members. That
556         * means the compiler is instructed to add no memory spaces between the
557         * individual members. Because by default the compiler might add memory
558         * spaces between individual members to align them on certain memory address
559         * boundaries for increasing runtime performance while accessing the
560         * members. So if you declared the previous example without the "packed"
561         * attribute like:
562         * @code
563         * #include <stdint.h>
564         * struct Foo {
565         *     int32_t a;
566         *     bool b;
567         *     double c;
568         * };
569         * @endcode
570         * then this method would usually return a different offset for members
571         * @c b and @c c instead. For most 64 bit architectures this example would
572         * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
573         * for member @c c.
574         */
575        size_t Member::offset() const {
576            return m_offset;
577        }
578    
579        /** @brief C/C++ Data type of this member.
580         *
581         * Returns the precise data type of the original native C/C++ member.
582         */
583        const DataType& Member::type() const {
584            return m_type;
585        }
586    
587        /** @brief Check if this is a valid Member object.
588         *
589         * Returns @c true if this Member object is reflecting a "valid" member
590         * object. The default constructor creates Member objects initialized to be
591         * "invalid" Member objects by default. That way one can detect whether
592         * a Member object was ever assigned to something meaningful.
593         *
594         * Note that this class also implements the @c bool operator, both return
595         * the same boolean result value.
596         */
597      bool Member::isValid() const {      bool Member::isValid() const {
598          return m_uid && !m_name.empty() && m_type;          return m_uid && !m_name.empty() && m_type;
599      }      }
600    
601        /** @brief Comparison for equalness.
602         *
603         * Returns @c true if the two Member objects being compared can be
604         * considered to be "equal" C/C++ members. They are considered to be
605         * equal if their data type, member name, their offset within their parent
606         * containing C/C++ data structure, as well as their original native C/C++
607         * instance were exactly identical.
608         */
609      bool Member::operator==(const Member& other) const {      bool Member::operator==(const Member& other) const {
610          return m_uid    == other.m_uid &&          return m_uid    == other.m_uid &&
611                 m_offset == other.m_offset &&                 m_offset == other.m_offset &&
# Line 159  namespace Serialization { Line 613  namespace Serialization {
613                 m_type   == other.m_type;                 m_type   == other.m_type;
614      }      }
615    
616        /** @brief Comparison for inequalness.
617         *
618         * Returns the inverse result of what Member::operator==() would return.
619         * So refer to the latter for more details.
620         */
621      bool Member::operator!=(const Member& other) const {      bool Member::operator!=(const Member& other) const {
622          return !operator==(other);          return !operator==(other);
623      }      }
624    
625        /** @brief Smaller than comparison.
626         *
627         * Returns @c true if this Member object can be consider to be "smaller"
628         * than the @a other Member object being compared with. This operator
629         * is actually quite arbitrarily implemented and may change at any time,
630         * and thus result for the same member representations may change in
631         * future at any time.
632         *
633         * This operator is basically implemented for allowing this DataType class
634         * to be used with various standard template library (STL) classes, which
635         * require sorting operators to be implemented.
636         */
637      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
638          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
639                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
640                 m_offset  < other.m_offset ||                (m_offset  < other.m_offset ||
641                (m_offset == other.m_offset &&                (m_offset == other.m_offset &&
642                 m_name  < other.m_name ||                (m_name  < other.m_name ||
643                (m_name == other.m_name &&                (m_name == other.m_name &&
644                 m_type < other.m_type)));                 m_type < other.m_type)))));
645      }      }
646    
647        /** @brief Greater than comparison.
648         *
649         * Returns @c true if this Member object can be consider to be "greater"
650         * than the @a other Member object being compared with. This operator
651         * is actually quite arbitrarily implemented and may change at any time,
652         * and thus result for the same member representations may change in
653         * future at any time.
654         *
655         * This operator is basically implemented for allowing this DataType class
656         * to be used with various standard template library (STL) classes, which
657         * require sorting operators to be implemented.
658         */
659      bool Member::operator>(const Member& other) const {      bool Member::operator>(const Member& other) const {
660          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
661      }      }
# Line 180  namespace Serialization { Line 663  namespace Serialization {
663      // *************** Object ***************      // *************** Object ***************
664      // *      // *
665    
666        /** @brief Default constructor (for an "invalid" Object).
667         *
668         * Initializes an Object instance as being an "invalid" Object.
669         * Thus calling isValid(), after creating an Object instance with this
670         * constructor, would return @c false.
671         *
672         * Usually you are not supposed to create (meaningful) Object instances on
673         * your own. They are typically constructed by the Archive class for you.
674         *
675         * @see Archive::rootObject(), Archive::objectByUID()
676         */
677      Object::Object() {      Object::Object() {
678          m_version = 0;          m_version = 0;
679          m_minVersion = 0;          m_minVersion = 0;
680      }      }
681    
682        /** @brief Constructor for a "meaningful" Object.
683         *
684         * Initializes a "meaningful" Object instance as being. Thus calling
685         * isValid(), after creating an Object instance with this constructor,
686         * should return @c true, provided that the arguments passed to this
687         * constructor construe a valid object representation.
688         *
689         * Usually you are not supposed to create (meaningful) Object instances on
690         * your own. They are typically constructed by the Archive class for you.
691         *
692         * @see Archive::rootObject(), Archive::objectByUID()
693         *
694         * @param uidChain - unique identifier chain of the object to be constructed
695         * @param type - C/C++ data type of the actual native object this abstract
696         *               Object instance should reflect after calling this
697         *               constructor
698         */
699      Object::Object(UIDChain uidChain, DataType type) {      Object::Object(UIDChain uidChain, DataType type) {
700          m_type = type;          m_type = type;
701          m_uid  = uidChain;          m_uid  = uidChain;
# Line 193  namespace Serialization { Line 704  namespace Serialization {
704          //m_data.resize(type.size());          //m_data.resize(type.size());
705      }      }
706    
707        /** @brief Check if this is a valid Object instance.
708         *
709         * Returns @c true if this Object instance is reflecting a "valid" Object.
710         * The default constructor creates Object instances initialized to be
711         * "invalid" Objects by default. That way one can detect whether an Object
712         * instance was ever assigned to something meaningful.
713         *
714         * Note that this class also implements the @c bool operator, both return
715         * the same boolean result value.
716         */
717      bool Object::isValid() const {      bool Object::isValid() const {
718          return m_type && !m_uid.empty();          return m_type && !m_uid.empty();
719      }      }
720    
721        /** @brief Unique identifier of this Object.
722         *
723         * Returns the unique identifier for the original native C/C++ data this
724         * abstract Object instance is reflecting. If this Object is representing
725         * a C/C++ pointer (of first degree) then @c uid() (or @c uid(0) ) returns
726         * the unique identifier of the pointer itself, whereas @c uid(1) returns
727         * the unique identifier of the original C/C++ data that pointer was
728         * actually pointing to.
729         *
730         * @see UIDChain for more details about this overall topic.
731         */
732        UID Object::uid(int index) const {
733            return (index < m_uid.size()) ? m_uid[index] : NO_UID;
734        }
735    
736        /** @brief Unique identifier chain of this Object.
737         *
738         * Returns the entire unique identifier chain of this Object.
739         *
740         * @see uid() and UIDChain for more details about this overall topic.
741         */
742        const UIDChain& Object::uidChain() const {
743            return m_uid;
744        }
745    
746        /** @brief C/C++ data type this Object is reflecting.
747         *
748         * Returns the precise original C/C++ data type of the original native
749         * C/C++ object or data this Object instance is reflecting.
750         */
751        const DataType& Object::type() const {
752            return m_type;
753        }
754    
755        /** @brief Raw data of the original native C/C++ data.
756         *
757         * Returns the raw data value of the original C/C++ data this Object is
758         * reflecting. So the precise raw data value, layout and size is dependent
759         * to the precise C/C++ data type of the original native C/C++ data. However
760         * potentially required endian correction is already automatically applied
761         * for you. That means you can safely, directly C-cast the raw data returned
762         * by this method to the respective native C/C++ data type in order to
763         * access and use the value for some purpose, at least if the respective
764         * data is of any fundamental, primitive C/C++ data type, or also to a
765         * certain extent if the type is user defined @c enum type.
766         *
767         * However directly C-casting this raw data for user defined @c struct or
768         * @c class types is not possible. For those user defined data structures
769         * this method always returns empty raw data instead.
770         *
771         * Note however that there are more convenient methods in the Archive class
772         * to get the right value for the individual data types instead.
773         *
774         * @see Archive::valueAsInt(), Archive::valueAsReal(), Archive::valueAsBool(),
775         *      Archive::valueAsString()
776         */
777        const RawData& Object::rawData() const {
778            return m_data;
779        }
780    
781        /** @brief Version of original user defined C/C++ @c struct or @c class.
782         *
783         * In case this Object is reflecting a native C/C++ @c struct or @c class
784         * type, then this method returns the version of that native C/C++ @c struct
785         * or @c class layout or implementation. For primitive, fundamental C/C++
786         * data types (including @c String objects) the return value of this method
787         * has no meaning.
788         *
789         * @see Archive::setVersion() for more details about this overall topic.
790         */
791        Version Object::version() const {
792            return m_version;
793        }
794    
795        /** @brief Minimum version of original user defined C/C++ @c struct or @c class.
796         *
797         * In case this Object is reflecting a native C/C++ @c struct or @c class
798         * type, then this method returns the "minimum" version of that native C/C++
799         * @c struct or @c class layout or implementation which it may be compatible
800         * with. For primitive, fundamental C/C++ data types (including @c String
801         * objects) the return value of this method has no meaning.
802         *
803         * @see Archive::setVersion() and Archive::setMinVersion() for more details
804         *      about this overall topic.
805         */
806        Version Object::minVersion() const {
807            return m_minVersion;
808        }
809    
810        /** @brief All members of the original native C/C++ @c struct or @c class instance.
811         *
812         * In case this Object is reflecting a native C/C++ @c struct or @c class
813         * type, then this method returns all member variables of that original
814         * native C/C++ @c struct or @c class instance. For primitive, fundamental
815         * C/C++ data types this method returns an empty vector instead.
816         *
817         * Example:
818         * @code
819         * struct Foo {
820         *     int  a;
821         *     bool b;
822         *     double someValue;
823         * };
824         * @endcode
825         * Considering above's C++ code, a serialized Object representation of such
826         * a native @c Foo class would have 3 members @c a, @c b and @c someValue.
827         *
828         * Note that the respective serialize() method implementation of that
829         * fictional C++ @c struct @c Foo actually defines which members are going
830         * to be serialized and deserialized for instances of class @c Foo. So in
831         * practice the members returned by method members() here might return a
832         * different set of members as actually defined in the original C/C++ struct
833         * header declaration.
834         *
835         * The precise sequence of the members returned by this method here depends
836         * on the actual serialize() implementation of the user defined C/C++
837         * @c struct or @c class.
838         *
839         * @see Object::sequenceIndexOf() for more details about the precise order
840         *      of members returned by this method in the same way.
841         */
842        std::vector<Member>& Object::members() {
843            return m_members;
844        }
845    
846        /** @brief All members of the original native C/C++ @c struct or @c class instance (read only).
847         *
848         * Returns the same result as overridden members() method above, it just
849         * returns a read-only result instead. See above's method description for
850         * details for the return value of this method instead.
851         */
852        const std::vector<Member>& Object::members() const {
853            return m_members;
854        }
855    
856        /** @brief Comparison for equalness.
857         *
858         * Returns @c true if the two Object instances being compared can be
859         * considered to be "equal" native C/C++ object instances. They are
860         * considered to be equal if they are representing the same original
861         * C/C++ data instance, which is essentially the case if the original
862         * reflecting native C/C++ data are sharing the same memory address and
863         * memory size (thus the exact same memory space) and originally had the
864         * exact same native C/C++ types.
865         */
866      bool Object::operator==(const Object& other) const {      bool Object::operator==(const Object& other) const {
867          // ignoring all other member variables here          // ignoring all other member variables here
868          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 204  namespace Serialization { Line 870  namespace Serialization {
870                 m_type == other.m_type;                 m_type == other.m_type;
871      }      }
872    
873        /** @brief Comparison for inequalness.
874         *
875         * Returns the inverse result of what Object::operator==() would return.
876         * So refer to the latter for more details.
877         */
878      bool Object::operator!=(const Object& other) const {      bool Object::operator!=(const Object& other) const {
879          return !operator==(other);          return !operator==(other);
880      }      }
881    
882        /** @brief Smaller than comparison.
883         *
884         * Returns @c true if this Object instance can be consider to be "smaller"
885         * than the @a other Object instance being compared with. This operator
886         * is actually quite arbitrarily implemented and may change at any time,
887         * and thus result for the same Object representations may change in future
888         * at any time.
889         *
890         * This operator is basically implemented for allowing this DataType class
891         * to be used with various standard template library (STL) classes, which
892         * require sorting operators to be implemented.
893         */
894      bool Object::operator<(const Object& other) const {      bool Object::operator<(const Object& other) const {
895          // ignoring all other member variables here          // ignoring all other member variables here
896          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 216  namespace Serialization { Line 899  namespace Serialization {
899                 m_type < other.m_type);                 m_type < other.m_type);
900      }      }
901    
902        /** @brief Greater than comparison.
903         *
904         * Returns @c true if this Object instance can be consider to be "greater"
905         * than the @a other Object instance being compared with. This operator
906         * is actually quite arbitrarily implemented and may change at any time,
907         * and thus result for the same Object representations may change in future
908         * at any time.
909         *
910         * This operator is basically implemented for allowing this DataType class
911         * to be used with various standard template library (STL) classes, which
912         * require sorting operators to be implemented.
913         */
914      bool Object::operator>(const Object& other) const {      bool Object::operator>(const Object& other) const {
915          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
916      }      }
917    
918        /** @brief Check version compatibility between Object instances.
919         *
920         * Use this method to check whether the two original C/C++ instances those
921         * two Objects are reflecting, were using a C/C++ data type which are version
922         * compatible with each other. By default all C/C++ Objects are considered
923         * to be version compatible. They might only be version incompatible if you
924         * enforced a certain backward compatibility constraint with your
925         * serialize() method implementation of your custom C/C++ @c struct or
926         * @c class types.
927         *
928         * You must only call this method on two Object instances which are
929         * representing the same data type, for example if both Objects reflect
930         * instances of the same user defined C++ class. Calling this method on
931         * completely different data types does not cause an error or exception, but
932         * its result would simply be useless for any purpose.
933         *
934         * @see Archive::setVersion() for more details about this overall topic.
935         */
936      bool Object::isVersionCompatibleTo(const Object& other) const {      bool Object::isVersionCompatibleTo(const Object& other) const {
937          if (this->version() == other.version())          if (this->version() == other.version())
938              return true;              return true;
# Line 229  namespace Serialization { Line 942  namespace Serialization {
942              return other.minVersion() <= this->version();              return other.minVersion() <= this->version();
943      }      }
944    
945        void Object::setVersion(Version v) {
946            m_version = v;
947        }
948    
949        void Object::setMinVersion(Version v) {
950            m_minVersion = v;
951        }
952    
953        /** @brief Get the member of this Object with given name.
954         *
955         * In case this Object is reflecting a native C/C++ @c struct or @c class
956         * type, then this method returns the abstract reflection of the requested
957         * member variable of the original native C/C++ @c struct or @c class
958         * instance. For primitive, fundamental C/C++ data types this method always
959         * returns an "invalid" Member instance instead.
960         *
961         * Example:
962         * @code
963         * struct Foo {
964         *     int  a;
965         *     bool b;
966         *     double someValue;
967         * };
968         * @endcode
969         * Consider that you serialized the native C/C++ @c struct as shown in this
970         * example, and assuming that you implemented the respective serialize()
971         * method of this C++ @c struct to serialize all its members, then you might
972         * call memberNamed("someValue") to get the details of the third member in
973         * this example for instance. In case the passed @a name is an unknown
974         * member name, then this method will return an "invalid" Member object
975         * instead.
976         *
977         * @param name - original name of the sought serialized member variable of
978         *               this Object reflection
979         * @returns abstract reflection of the sought member variable
980         * @see Member::isValid(), Object::members()
981         */
982      Member Object::memberNamed(String name) const {      Member Object::memberNamed(String name) const {
983          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
984              if (m_members[i].name() == name)              if (m_members[i].name() == name)
# Line 236  namespace Serialization { Line 986  namespace Serialization {
986          return Member();          return Member();
987      }      }
988    
989        /** @brief Get the member of this Object with given unique identifier.
990         *
991         * This method behaves similar like method memberNamed() described above,
992         * but instead of searching for a member variable by name, it searches for
993         * a member with an abstract unique identifier instead. For primitive,
994         * fundamental C/C++ data types, for invalid or unknown unique identifiers,
995         * and for members which are actually not member instances of the original
996         * C/C++ @c struct or @c class instance this Object is reflecting, this
997         * method returns an "invalid" Member instance instead.
998         *
999         * @param uid - unique identifier of the member variable being sought
1000         * @returns abstract reflection of the sought member variable
1001         * @see Member::isValid(), Object::members(), Object::memberNamed()
1002         */
1003        Member Object::memberByUID(const UID& uid) const {
1004            if (!uid) return Member();
1005            for (int i = 0; i < m_members.size(); ++i)
1006                if (m_members[i].uid() == uid)
1007                    return m_members[i];
1008            return Member();
1009        }
1010    
1011      void Object::remove(const Member& member) {      void Object::remove(const Member& member) {
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 245  namespace Serialization { Line 1017  namespace Serialization {
1017          }          }
1018      }      }
1019    
1020        /** @brief Get all members of this Object with given data type.
1021         *
1022         * In case this Object is reflecting a native C/C++ @c struct or @c class
1023         * type, then this method returns all member variables of that original
1024         * native C/C++ @c struct or @c class instance which are matching the given
1025         * requested data @a type. If this Object is reflecting a primitive,
1026         * fundamental data type, or if there are no members of this Object with the
1027         * requested precise C/C++ data type, then this method returns an empty
1028         * vector instead.
1029         *
1030         * @param type - the precise C/C++ data type of the sought member variables
1031         *               of this Object
1032         * @returns vector with abstract reflections of the sought member variables
1033         * @see Object::members(), Object::memberNamed()
1034         */
1035      std::vector<Member> Object::membersOfType(const DataType& type) const {      std::vector<Member> Object::membersOfType(const DataType& type) const {
1036          std::vector<Member> v;          std::vector<Member> v;
1037          for (int i = 0; i < m_members.size(); ++i) {          for (int i = 0; i < m_members.size(); ++i) {
# Line 255  namespace Serialization { Line 1042  namespace Serialization {
1042          return v;          return v;
1043      }      }
1044    
1045        /** @brief Serialization/deserialization sequence number of the requested member.
1046         *
1047         * Returns the precise serialization/deserialization sequence number of the
1048         * requested @a member variable.
1049         *
1050         * Example:
1051         * @code
1052         * struct Foo {
1053         *     int  a;
1054         *     bool b;
1055         *     double c;
1056         *
1057         *     void serialize(Serialization::Archive* archive);
1058         * };
1059         * @endcode
1060         * Assuming the declaration of the user defined native C/C++ @c struct
1061         * @c Foo above, and assuming the following implementation of serialize():
1062         * @code
1063         * #define SRLZ(member) \
1064         *   archive->serializeMember(*this, member, #member);
1065         *
1066         * void Foo::serialize(Serialization::Archive* archive) {
1067         *     SRLZ(c);
1068         *     SRLZ(a);
1069         *     SRLZ(b);
1070         * }
1071         * @endcode
1072         * then @c sequenceIndexOf(obj.memberNamed("a")) returns 1,
1073         * @c sequenceIndexOf(obj.memberNamed("b")) returns 2, and
1074         * @c sequenceIndexOf(obj.memberNamed("c")) returns 0.
1075         */
1076      int Object::sequenceIndexOf(const Member& member) const {      int Object::sequenceIndexOf(const Member& member) const {
1077          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
1078              if (m_members[i] == member)              if (m_members[i] == member)
# Line 265  namespace Serialization { Line 1083  namespace Serialization {
1083      // *************** Archive ***************      // *************** Archive ***************
1084      // *      // *
1085    
1086        /** @brief Create an "empty" archive.
1087         *
1088         * This default constructor creates an "empty" archive which you then
1089         * subsequently for example might fill with serialized data like:
1090         * @code
1091         * Archive a;
1092         * a.serialize(&myRootObject);
1093         * @endcode
1094         * Or:
1095         * @code
1096         * Archive a;
1097         * a << myRootObject;
1098         * @endcode
1099         * Or you might also subsequently assign an already existing non-empty
1100         * to this empty archive, which effectively clones the other
1101         * archive (deep copy) or call decode() later on to assign a previously
1102         * serialized raw data stream.
1103         */
1104      Archive::Archive() {      Archive::Archive() {
1105          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1106          m_root = NO_UID;          m_root = NO_UID;
1107          m_isModified = false;          m_isModified = false;
1108            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1109      }      }
1110    
1111        /** @brief Create and fill the archive with the given serialized raw data.
1112         *
1113         * This constructor decodes the given raw @a data and constructs a
1114         * (non-empty) Archive object according to that given serialized data
1115         * stream.
1116         *
1117         * After this constructor returned, you may then traverse the individual
1118         * objects by starting with accessing the rootObject() for example. Finally
1119         * you might call deserialize() to restore your native C++ objects with the
1120         * content of this archive.
1121         *
1122         * @param data - the previously serialized raw data stream to be decoded
1123         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1124         *         incompatible or corrupt data stream or format.
1125         */
1126      Archive::Archive(const RawData& data) {      Archive::Archive(const RawData& data) {
1127          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1128          m_root = NO_UID;          m_root = NO_UID;
1129          m_isModified = false;          m_isModified = false;
1130          decode(m_rawData);          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1131            decode(data);
1132      }      }
1133    
1134        /** @brief Create and fill the archive with the given serialized raw C-buffer data.
1135         *
1136         * This constructor essentially works like the constructor above, but just
1137         * uses another data type for the serialized raw data stream being passed to
1138         * this class.
1139         *
1140         * This constructor decodes the given raw @a data and constructs a
1141         * (non-empty) Archive object according to that given serialized data
1142         * stream.
1143         *
1144         * After this constructor returned, you may then traverse the individual
1145         * objects by starting with accessing the rootObject() for example. Finally
1146         * you might call deserialize() to restore your native C++ objects with the
1147         * content of this archive.
1148         *
1149         * @param data - the previously serialized raw data stream to be decoded
1150         * @param size - size of @a data in bytes
1151         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1152         *         incompatible or corrupt data stream or format.
1153         */
1154      Archive::Archive(const uint8_t* data, size_t size) {      Archive::Archive(const uint8_t* data, size_t size) {
1155          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1156          m_root = NO_UID;          m_root = NO_UID;
1157          m_isModified = false;          m_isModified = false;
1158            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1159          decode(data, size);          decode(data, size);
1160      }      }
1161    
1162      Archive::~Archive() {      Archive::~Archive() {
1163      }      }
1164    
1165        /** @brief Root C++ object of this archive.
1166         *
1167         * In case this is a non-empty Archive, then this method returns the so
1168         * called "root" C++ object. If this is an empty archive, then this method
1169         * returns an "invalid" Object instance instead.
1170         *
1171         * @see Archive::serialize() for more details about the "root" object concept.
1172         * @see Object for more details about the overall object reflection concept.
1173         * @returns reflection of the original native C++ root object
1174         */
1175      Object& Archive::rootObject() {      Object& Archive::rootObject() {
1176          return m_allObjects[m_root];          return m_allObjects[m_root];
1177      }      }
# Line 303  namespace Serialization { Line 1187  namespace Serialization {
1187          return _encodeBlob(s);          return _encodeBlob(s);
1188      }      }
1189    
1190        static String _encode(const time_t& time) {
1191            return _encodeBlob(ToString(time));
1192        }
1193    
1194      static String _encode(const DataType& type) {      static String _encode(const DataType& type) {
1195          String s;          String s;
1196          s += _encodeBlob(type.baseTypeName());          s += _encodeBlob(type.baseTypeName());
# Line 376  namespace Serialization { Line 1264  namespace Serialization {
1264                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1265              } else if (type.isBool()) {              } else if (type.isBool()) {
1266                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1267                } else if (type.isString()) {
1268                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1269              } else {              } else {
1270                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1271              }              }
# Line 384  namespace Serialization { Line 1274  namespace Serialization {
1274          return s;          return s;
1275      }      }
1276    
1277        template<typename T>
1278        inline T _stringToNumber(const String& s) {
1279            assert(false /* String cast to unknown primitive number type */);
1280        }
1281    
1282        template<>
1283        inline int64_t _stringToNumber(const String& s) {
1284            return atoll(s.c_str());
1285        }
1286    
1287        template<>
1288        inline double _stringToNumber(const String& s) {
1289            return atof(s.c_str());
1290        }
1291    
1292        template<>
1293        inline bool _stringToNumber(const String& s) {
1294            return (bool) atoll(s.c_str());
1295        }
1296    
1297        template<typename T>
1298        static T _primitiveObjectValueToNumber(const Object& obj) {
1299            T value = 0;
1300            const DataType& type = obj.type();
1301            const ID& id = obj.uid().id;
1302            void* ptr = obj.m_data.empty() ? (void*)id : (void*)&obj.m_data[0];
1303            if (!obj.m_data.empty())
1304                assert(type.size() == obj.m_data.size());
1305            if (type.isPrimitive() && !type.isPointer()) {
1306                if (type.isInteger() || type.isEnum()) {
1307                    if (type.isSigned()) {
1308                        if (type.size() == 1)
1309                            value = (T)*(int8_t*)ptr;
1310                        else if (type.size() == 2)
1311                            value = (T)*(int16_t*)ptr;
1312                        else if (type.size() == 4)
1313                            value = (T)*(int32_t*)ptr;
1314                        else if (type.size() == 8)
1315                            value = (T)*(int64_t*)ptr;
1316                        else
1317                            assert(false /* unknown signed int type size */);
1318                    } else {
1319                        if (type.size() == 1)
1320                            value = (T)*(uint8_t*)ptr;
1321                        else if (type.size() == 2)
1322                            value = (T)*(uint16_t*)ptr;
1323                        else if (type.size() == 4)
1324                            value = (T)*(uint32_t*)ptr;
1325                        else if (type.size() == 8)
1326                            value = (T)*(uint64_t*)ptr;
1327                        else
1328                            assert(false /* unknown unsigned int type size */);
1329                    }
1330                } else if (type.isReal()) {
1331                    if (type.size() == sizeof(float))
1332                        value = (T)*(float*)ptr;
1333                    else if (type.size() == sizeof(double))
1334                        value = (T)*(double*)ptr;
1335                    else
1336                        assert(false /* unknown floating point type */);
1337                } else if (type.isBool()) {
1338                    value = (T)*(bool*)ptr;
1339                } else if (type.isString()) {
1340                    value = _stringToNumber<T>(
1341                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1342                    );
1343                } else {
1344                    assert(false /* unknown primitive type */);
1345                }
1346            }
1347            return value;
1348        }
1349    
1350      static String _encodePrimitiveValue(const Object& obj) {      static String _encodePrimitiveValue(const Object& obj) {
1351          return _encodeBlob( _primitiveObjectValueToString(obj) );          return _encodeBlob( _primitiveObjectValueToString(obj) );
1352      }      }
# Line 410  namespace Serialization { Line 1373  namespace Serialization {
1373          return _encodeBlob(s);          return _encodeBlob(s);
1374      }      }
1375    
1376        /*
1377         * Srx format history:
1378         * - 1.0: Initial version.
1379         * - 1.1: Adds "String" data type.
1380         */
1381      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1382      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1383    
1384      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1385          String s;          String s;
1386          s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));          s += _encodeBlob(ToString(ENCODING_FORMAT_MINOR_VERSION));
1387          s += _encode(m_root);          s += _encode(m_root);
1388          s += _encode(m_allObjects);          s += _encode(m_allObjects);
1389            s += _encodeBlob(m_name);
1390            s += _encodeBlob(m_comment);
1391            s += _encode(m_timeCreated);
1392            s += _encode(m_timeModified);
1393          return _encodeBlob(s);          return _encodeBlob(s);
1394      }      }
1395    
1396      void Archive::encode() {      void Archive::encode() {
1397          m_rawData.clear();          m_rawData.clear();
1398          String s = MAGIC_START;          String s = MAGIC_START;
1399            m_timeModified = time(NULL);
1400            if (m_timeCreated == LIBGIG_EPOCH_TIME)
1401                m_timeCreated = m_timeModified;
1402          s += _encodeRootBlob();          s += _encodeRootBlob();
1403          m_rawData.resize(s.length() + 1);          m_rawData.resize(s.length() + 1);
1404          memcpy(&m_rawData[0], &s[0], s.length() + 1);          memcpy(&m_rawData[0], &s[0], s.length() + 1);
# Line 436  namespace Serialization { Line 1411  namespace Serialization {
1411      };      };
1412    
1413      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {      static _Blob _decodeBlob(const char* p, const char* end, bool bThrow = true) {
1414          if (!bThrow && p >= end)          if (!bThrow && p >= end) {
1415              return (_Blob) { p, end };              const _Blob blob =  { p, end };
1416                return blob;
1417            }
1418          size_t sz = 0;          size_t sz = 0;
1419          for (; true; ++p) {          for (; true; ++p) {
1420              if (p >= end)              if (p >= end)
# Line 452  namespace Serialization { Line 1429  namespace Serialization {
1429          ++p;          ++p;
1430          if (p + sz > end)          if (p + sz > end)
1431              throw Exception("Decode Error: Premature end of blob");              throw Exception("Decode Error: Premature end of blob");
1432          return (_Blob) { p, p + sz };          const _Blob blob = { p, p + sz };
1433            return blob;
1434      }      }
1435    
1436      template<typename T_int>      template<typename T_int>
# Line 527  namespace Serialization { Line 1505  namespace Serialization {
1505          return s;          return s;
1506      }      }
1507    
1508      DataType _popDataTypeBlob(const char*& p, const char* end) {      static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1509            String s = _popStringBlob(p, end);
1510            rawData.resize(s.length() + 1);
1511            strcpy((char*)&rawData[0], &s[0]);
1512        }
1513    
1514        static time_t _popTimeBlob(const char*& p, const char* end) {
1515            const uint64_t i = _popIntBlob<uint64_t>(p, end);
1516            return (time_t) i;
1517        }
1518    
1519        static DataType _popDataTypeBlob(const char*& p, const char* end) {
1520          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1521          p   = blob.p;          p   = blob.p;
1522          end = blob.end;          end = blob.end;
# Line 551  namespace Serialization { Line 1540  namespace Serialization {
1540          const ID id = (ID) _popIntBlob<size_t>(p, end);          const ID id = (ID) _popIntBlob<size_t>(p, end);
1541          const size_t size = _popIntBlob<size_t>(p, end);          const size_t size = _popIntBlob<size_t>(p, end);
1542    
1543          return (UID) { id, size };          const UID uid = { id, size };
1544            return uid;
1545      }      }
1546    
1547      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {      static UIDChain _popUIDChainBlob(const char*& p, const char* end) {
# Line 639  namespace Serialization { Line 1629  namespace Serialization {
1629                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1630              } else if (type.isBool()) {              } else if (type.isBool()) {
1631                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1632                } else if (type.isString()) {
1633                    _popStringBlob(p, end, obj.m_data);
1634              } else {              } else {
1635                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1636              }              }
# Line 703  namespace Serialization { Line 1695  namespace Serialization {
1695          _popObjectsBlob(p, end);          _popObjectsBlob(p, end);
1696          if (!m_allObjects[m_root])          if (!m_allObjects[m_root])
1697              throw Exception("Decode Error: Missing declared root object");              throw Exception("Decode Error: Missing declared root object");
     }  
1698    
1699            m_name = _popStringBlob(p, end);
1700            m_comment = _popStringBlob(p, end);
1701            m_timeCreated = _popTimeBlob(p, end);
1702            m_timeModified = _popTimeBlob(p, end);
1703        }
1704    
1705        /** @brief Fill this archive with the given serialized raw data.
1706         *
1707         * Calling this method will decode the given raw @a data and constructs a
1708         * (non-empty) Archive object according to that given serialized @a data
1709         * stream.
1710         *
1711         * After this method returned, you may then traverse the individual
1712         * objects by starting with accessing the rootObject() for example. Finally
1713         * you might call deserialize() to restore your native C++ objects with the
1714         * content of this archive.
1715         *
1716         * @param data - the previously serialized raw data stream to be decoded
1717         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1718         *         incompatible or corrupt data stream or format.
1719         */
1720      void Archive::decode(const RawData& data) {      void Archive::decode(const RawData& data) {
1721          m_rawData = data;          m_rawData = data;
1722          m_allObjects.clear();          m_allObjects.clear();
1723          m_isModified = false;          m_isModified = false;
1724            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1725          const char* p   = (const char*) &data[0];          const char* p   = (const char*) &data[0];
1726          const char* end = p + data.size();          const char* end = p + data.size();
1727          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 1730  namespace Serialization {
1730          _popRootBlob(p, end);          _popRootBlob(p, end);
1731      }      }
1732    
1733        /** @brief Fill this archive with the given serialized raw C-buffer data.
1734         *
1735         * This method essentially works like the decode() method above, but just
1736         * uses another data type for the serialized raw data stream being passed to
1737         * this method.
1738         *
1739         * Calling this method will decode the given raw @a data and constructs a
1740         * (non-empty) Archive object according to that given serialized @a data
1741         * stream.
1742         *
1743         * After this method returned, you may then traverse the individual
1744         * objects by starting with accessing the rootObject() for example. Finally
1745         * you might call deserialize() to restore your native C++ objects with the
1746         * content of this archive.
1747         *
1748         * @param data - the previously serialized raw data stream to be decoded
1749         * @param size - size of @a data in bytes
1750         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1751         *         incompatible or corrupt data stream or format.
1752         */
1753      void Archive::decode(const uint8_t* data, size_t size) {      void Archive::decode(const uint8_t* data, size_t size) {
1754          RawData rawData;          RawData rawData;
1755          rawData.resize(size);          rawData.resize(size);
# Line 724  namespace Serialization { Line 1757  namespace Serialization {
1757          decode(rawData);          decode(rawData);
1758      }      }
1759    
1760        /** @brief Raw data stream of this archive content.
1761         *
1762         * Call this method to get a raw data stream for the current content of this
1763         * archive, which you may use to i.e. store on disk or send vie network to
1764         * another machine for deserializing there. This method only returns a
1765         * meaningful content if this is a non-empty archive, that is if you either
1766         * serialized with this Archive object or decoded a raw data stream to this
1767         * Archive object before. If this is an empty archive instead, then this
1768         * method simply returns an empty raw data stream (of size 0) instead.
1769         *
1770         * Note that whenever you call this method, the "modified" state of this
1771         * archive will be reset to @c false.
1772         *
1773         * @see isModified()
1774         */
1775      const RawData& Archive::rawData() {      const RawData& Archive::rawData() {
1776          if (m_isModified) encode();          if (m_isModified) encode();
1777          return m_rawData;          return m_rawData;
1778      }      }
1779    
1780        /** @brief Name of the encoding format used by this Archive class.
1781         *
1782         * This method returns the name of the encoding format used to encode
1783         * serialized raw data streams.
1784         */
1785      String Archive::rawDataFormat() const {      String Archive::rawDataFormat() const {
1786          return MAGIC_START;          return MAGIC_START;
1787      }      }
1788    
1789        /** @brief Whether this archive was modified.
1790         *
1791         * This method returns the current "modified" state of this archive. When
1792         * either decoding a previously serialized raw data stream or after
1793         * serializing native C++ objects to this archive the modified state will
1794         * initially be set to @c false. However whenever you are modifying the
1795         * abstract data model of this archive afterwards, for example by removing
1796         * objects from this archive by calling remove() or removeMember(), or by
1797         * altering object values for example by calling setIntValue(), then the
1798         * "modified" state of this archive will automatically be set to @c true.
1799         *
1800         * You can reset the "modified" state explicitly at any time, by calling
1801         * rawData().
1802         */
1803      bool Archive::isModified() const {      bool Archive::isModified() const {
1804          return m_isModified;          return m_isModified;
1805      }      }
1806    
1807        /** @brief Clear content of this archive.
1808         *
1809         * Drops the entire content of this archive and thus resets this archive
1810         * back to become an empty archive.
1811         */
1812      void Archive::clear() {      void Archive::clear() {
1813          m_allObjects.clear();          m_allObjects.clear();
1814          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1815          m_root = NO_UID;          m_root = NO_UID;
1816          m_rawData.clear();          m_rawData.clear();
1817          m_isModified = false;          m_isModified = false;
1818            m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1819        }
1820    
1821        /** @brief Optional name of this archive.
1822         *
1823         * Returns the optional name of this archive that you might have assigned
1824         * to this archive before by calling setName(). If you haven't assigned any
1825         * name to this archive before, then this method simply returns an empty
1826         * string instead.
1827         */
1828        String Archive::name() const {
1829            return m_name;
1830        }
1831    
1832        /** @brief Assign a name to this archive.
1833         *
1834         * You may optionally assign an arbitrary name to this archive. The name
1835         * will be stored along with the archive, that is it will encoded with the
1836         * resulting raw data stream, and accordingly it will be decoded from the
1837         * raw data stream later on.
1838         *
1839         * @param name - arbitrary new name for this archive
1840         */
1841        void Archive::setName(String name) {
1842            if (m_name == name) return;
1843            m_name = name;
1844            m_isModified = true;
1845        }
1846    
1847        /** @brief Optional comments for this archive.
1848         *
1849         * Returns the optional comments for this archive that you might have
1850         * assigned to this archive before by calling setComment(). If you haven't
1851         * assigned any comment to this archive before, then this method simply
1852         * returns an empty string instead.
1853         */
1854        String Archive::comment() const {
1855            return m_comment;
1856        }
1857    
1858        /** @brief Assign a comment to this archive.
1859         *
1860         * You may optionally assign arbitrary comments to this archive. The comment
1861         * will be stored along with the archive, that is it will encoded with the
1862         * resulting raw data stream, and accordingly it will be decoded from the
1863         * raw data stream later on.
1864         *
1865         * @param comment - arbitrary new comment for this archive
1866         */
1867        void Archive::setComment(String comment) {
1868            if (m_comment == comment) return;
1869            m_comment = comment;
1870            m_isModified = true;
1871      }      }
1872    
1873        static tm _convertTimeStamp(const time_t& time, time_base_t base) {
1874            tm* pTm;
1875            switch (base) {
1876                case LOCAL_TIME:
1877                    pTm = localtime(&time);
1878                    break;
1879                case UTC_TIME:
1880                    pTm = gmtime(&time);
1881                    break;
1882                default:
1883                    throw Exception("Time stamp with unknown time base (" + ToString((int64_t)base) + ") requested");
1884            }
1885            if (!pTm)
1886                throw Exception("Failed assembling time stamp structure");
1887            return *pTm;
1888        }
1889    
1890        /** @brief Date and time when this archive was initially created.
1891         *
1892         * Returns a UTC time stamp (date and time) when this archive was initially
1893         * created.
1894         */
1895        time_t Archive::timeStampCreated() const {
1896            return m_timeCreated;
1897        }
1898    
1899        /** @brief Date and time when this archive was modified for the last time.
1900         *
1901         * Returns a UTC time stamp (date and time) when this archive was modified
1902         * for the last time.
1903         */
1904        time_t Archive::timeStampModified() const {
1905            return m_timeModified;
1906        }
1907    
1908        /** @brief Date and time when this archive was initially created.
1909         *
1910         * Returns a calendar time information representing the date and time when
1911         * this archive was initially created. The optional @a base parameter may
1912         * be used to define to which time zone the returned data and time shall be
1913         * related to.
1914         *
1915         * @param base - (optional) time zone the result shall relate to, by default
1916         *               UTC time (Greenwhich Mean Time) is assumed instead
1917         */
1918        tm Archive::dateTimeCreated(time_base_t base) const {
1919            return _convertTimeStamp(m_timeCreated, base);
1920        }
1921    
1922        /** @brief Date and time when this archive was modified for the last time.
1923         *
1924         * Returns a calendar time information representing the date and time when
1925         * this archive has been modified for the last time. The optional @a base
1926         * parameter may be used to define to which time zone the returned date and
1927         * time shall be related to.
1928         *
1929         * @param base - (optional) time zone the result shall relate to, by default
1930         *               UTC time (Greenwhich Mean Time) is assumed instead
1931         */
1932        tm Archive::dateTimeModified(time_base_t base) const {
1933            return _convertTimeStamp(m_timeModified, base);
1934        }
1935    
1936        /** @brief Remove a member variable from the given object.
1937         *
1938         * Removes the member variable @a member from its containing object
1939         * @a parent and sets the modified state of this archive to @c true.
1940         * If the given @a parent object does not contain the given @a member then
1941         * this method does nothing.
1942         *
1943         * This method provides a means of "partial" deserialization. By removing
1944         * either objects or members from this archive before calling deserialize(),
1945         * only the remaining objects and remaining members will be restored by this
1946         * framework, all other data of your C++ classes remain untouched.
1947         *
1948         * @param parent - Object which contains @a member
1949         * @param member - member to be removed
1950         * @see isModified() for details about the modified state.
1951         * @see Object for more details about the overall object reflection concept.
1952         */
1953        void Archive::removeMember(Object& parent, const Member& member) {
1954            parent.remove(member);
1955            m_isModified = true;
1956        }
1957    
1958        /** @brief Remove an object from this archive.
1959         *
1960         * Removes the object @obj from this archive and sets the modified state of
1961         * this archive to @c true. If the passed object is either invalid, or does
1962         * not exist in this archive, then this method does nothing.
1963         *
1964         * This method provides a means of "partial" deserialization. By removing
1965         * either objects or members from this archive before calling deserialize(),
1966         * only the remaining objects and remaining members will be restored by this
1967         * framework, all other data of your C++ classes remain untouched.
1968         *
1969         * @param obj - the object to be removed from this archive
1970         * @see isModified() for details about the modified state.
1971         * @see Object for more details about the overall object reflection concept.
1972         */
1973      void Archive::remove(const Object& obj) {      void Archive::remove(const Object& obj) {
1974            //FIXME: Should traverse from root object and remove all members associated with this object
1975          if (!obj.uid()) return;          if (!obj.uid()) return;
1976          m_allObjects.erase(obj.uid());          m_allObjects.erase(obj.uid());
1977          m_isModified = true;          m_isModified = true;
1978      }      }
1979    
1980        /** @brief Access object by its unique identifier.
1981         *
1982         * Returns the object of this archive with the given unique identifier
1983         * @a uid. If the given @a uid is invalid, or if this archive does not
1984         * contain an object with the given unique identifier, then this method
1985         * returns an invalid object instead.
1986         *
1987         * @param uid - unique identifier of sought object
1988         * @see Object for more details about the overall object reflection concept.
1989         * @see Object::isValid() for valid/invalid objects
1990         */
1991      Object& Archive::objectByUID(const UID& uid) {      Object& Archive::objectByUID(const UID& uid) {
1992          return m_allObjects[uid];          return m_allObjects[uid];
1993      }      }
1994    
1995        /** @brief Set the current version for the given object.
1996         *
1997         * Essentially behaves like above's setVersion() method, it just uses the
1998         * abstract reflection data type instead for the respective @a object being
1999         * passed to this method. Refer to above's setVersion() documentation about
2000         * the precise behavior details of setVersion().
2001         *
2002         * @param object - object to set the current version for
2003         * @param v - new current version to set for @a object
2004         */
2005        void Archive::setVersion(Object& object, Version v) {
2006            if (!object) return;
2007            object.setVersion(v);
2008            m_isModified = true;
2009        }
2010    
2011        /** @brief Set the minimum version for the given object.
2012         *
2013         * Essentially behaves like above's setMinVersion() method, it just uses the
2014         * abstract reflection data type instead for the respective @a object being
2015         * passed to this method. Refer to above's setMinVersion() documentation
2016         * about the precise behavior details of setMinVersion().
2017         *
2018         * @param object - object to set the minimum version for
2019         * @param v - new minimum version to set for @a object
2020         */
2021        void Archive::setMinVersion(Object& object, Version v) {
2022            if (!object) return;
2023            object.setMinVersion(v);
2024            m_isModified = true;
2025        }
2026    
2027        /** @brief Set new value for given @c enum object.
2028         *
2029         * Sets the new @a value to the given @c enum @a object.
2030         *
2031         * @param object - the @c enum object to be changed
2032         * @param value - the new value to be assigned to the @a object
2033         * @throws Exception if @a object is not an @c enum type.
2034         */
2035      void Archive::setEnumValue(Object& object, uint64_t value) {      void Archive::setEnumValue(Object& object, uint64_t value) {
2036          if (!object) return;          if (!object) return;
2037          if (!object.type().isEnum())          if (!object.type().isEnum())
# Line 787  namespace Serialization { Line 2064  namespace Serialization {
2064          m_isModified = true;          m_isModified = true;
2065      }      }
2066    
2067        /** @brief Set new integer value for given integer object.
2068         *
2069         * Sets the new integer @a value to the given integer @a object. Currently
2070         * this framework handles any integer data type up to 64 bit. For larger
2071         * integer types an assertion failure will be raised.
2072         *
2073         * @param object - the integer object to be changed
2074         * @param value - the new value to be assigned to the @a object
2075         * @throws Exception if @a object is not an integer type.
2076         */
2077      void Archive::setIntValue(Object& object, int64_t value) {      void Archive::setIntValue(Object& object, int64_t value) {
2078          if (!object) return;          if (!object) return;
2079          if (!object.type().isInteger())          if (!object.type().isInteger())
# Line 826  namespace Serialization { Line 2113  namespace Serialization {
2113          m_isModified = true;          m_isModified = true;
2114      }      }
2115    
2116        /** @brief Set new floating point value for given floating point object.
2117         *
2118         * Sets the new floating point @a value to the given floating point
2119         * @a object. Currently this framework supports single precision @c float
2120         * and double precision @c double floating point data types. For all other
2121         * floating point types this method will raise an assertion failure.
2122         *
2123         * @param object - the floating point object to be changed
2124         * @param value - the new value to be assigned to the @a object
2125         * @throws Exception if @a object is not a floating point based type.
2126         */
2127      void Archive::setRealValue(Object& object, double value) {      void Archive::setRealValue(Object& object, double value) {
2128          if (!object) return;          if (!object) return;
2129          if (!object.type().isReal())          if (!object.type().isReal())
# Line 848  namespace Serialization { Line 2146  namespace Serialization {
2146          m_isModified = true;          m_isModified = true;
2147      }      }
2148    
2149        /** @brief Set new boolean value for given boolean object.
2150         *
2151         * Sets the new boolean @a value to the given boolean @a object.
2152         *
2153         * @param object - the boolean object to be changed
2154         * @param value - the new value to be assigned to the @a object
2155         * @throws Exception if @a object is not a boolean type.
2156         */
2157      void Archive::setBoolValue(Object& object, bool value) {      void Archive::setBoolValue(Object& object, bool value) {
2158          if (!object) return;          if (!object) return;
2159          if (!object.type().isBool())          if (!object.type().isBool())
# Line 865  namespace Serialization { Line 2171  namespace Serialization {
2171          m_isModified = true;          m_isModified = true;
2172      }      }
2173    
2174        /** @brief Set new textual string for given String object.
2175         *
2176         * Sets the new textual string @a value to the given String @a object.
2177         *
2178         * @param object - the String object to be changed
2179         * @param value - the new textual string to be assigned to the @a object
2180         * @throws Exception if @a object is not a String type.
2181         */
2182        void Archive::setStringValue(Object& object, String value) {
2183            if (!object) return;
2184            if (!object.type().isString())
2185                throw Exception("Not a String data type");
2186            Object* pObject = &object;
2187            if (object.type().isPointer()) {
2188                Object& obj = objectByUID(object.uid(1));
2189                if (!obj) return;
2190                pObject = &obj;
2191            }
2192            pObject->m_data.resize(value.length() + 1);
2193            char* ptr = (char*) &pObject->m_data[0];
2194            strcpy(ptr, &value[0]);
2195            m_isModified = true;
2196        }
2197    
2198        /** @brief Automatically cast and assign appropriate value to object.
2199         *
2200         * This method automatically converts the given @a value from textual string
2201         * representation into the appropriate data format of the requested
2202         * @a object. So this method is a convenient way to change values of objects
2203         * in this archive with your applications in automated way, i.e. for
2204         * implementing an editor where the user is able to edit values of objects
2205         * in this archive by entering the values as text with a keyboard.
2206         *
2207         * @throws Exception if the passed @a object is not a fundamental, primitive
2208         *         data type or if the provided textual value cannot be converted
2209         *         into an appropriate value for the requested object.
2210         */
2211      void Archive::setAutoValue(Object& object, String value) {      void Archive::setAutoValue(Object& object, String value) {
2212          if (!object) return;          if (!object) return;
2213          const DataType& type = object.type();          const DataType& type = object.type();
# Line 872  namespace Serialization { Line 2215  namespace Serialization {
2215              setIntValue(object, atoll(value.c_str()));              setIntValue(object, atoll(value.c_str()));
2216          else if (type.isReal())          else if (type.isReal())
2217              setRealValue(object, atof(value.c_str()));              setRealValue(object, atof(value.c_str()));
2218          else if (type.isBool())          else if (type.isBool()) {
2219              setBoolValue(object, atof(value.c_str()));              String val = toLowerCase(value);
2220                if (val == "true" || val == "yes" || val == "1")
2221                    setBoolValue(object, true);
2222                else if (val == "false" || val == "no" || val == "0")
2223                    setBoolValue(object, false);
2224                else
2225                    setBoolValue(object, atof(value.c_str()));
2226            } else if (type.isString())
2227                setStringValue(object, value);
2228          else if (type.isEnum())          else if (type.isEnum())
2229              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2230          else          else
2231              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
2232      }      }
2233    
2234        /** @brief Get value of object as string.
2235         *
2236         * Converts the current value of the given @a object into a textual string
2237         * and returns that string.
2238         *
2239         * @param object - object whose value shall be retrieved
2240         * @throws Exception if the given object is either invalid, or if the object
2241         *         is not a fundamental, primitive data type.
2242         */
2243      String Archive::valueAsString(const Object& object) {      String Archive::valueAsString(const Object& object) {
2244          if (!object)          if (!object)
2245              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 894  namespace Serialization { Line 2254  namespace Serialization {
2254          return _primitiveObjectValueToString(*pObject);          return _primitiveObjectValueToString(*pObject);
2255      }      }
2256    
2257        /** @brief Get integer value of object.
2258         *
2259         * Returns the current integer value of the requested integer @a object or
2260         * @c enum object.
2261         *
2262         * @param object - object whose value shall be retrieved
2263         * @throws Exception if the given object is either invalid, or if the object
2264         *         is neither an integer nor @c enum data type.
2265         */
2266        int64_t Archive::valueAsInt(const Object& object) {
2267            if (!object)
2268                throw Exception("Invalid object");
2269            if (!object.type().isInteger() && !object.type().isEnum())
2270                throw Exception("Object is neither an integer nor an enum");
2271            const Object* pObject = &object;
2272            if (object.type().isPointer()) {
2273                const Object& obj = objectByUID(object.uid(1));
2274                if (!obj) return 0;
2275                pObject = &obj;
2276            }
2277            return _primitiveObjectValueToNumber<int64_t>(*pObject);
2278        }
2279    
2280        /** @brief Get floating point value of object.
2281         *
2282         * Returns the current floating point value of the requested floating point
2283         * @a object.
2284         *
2285         * @param object - object whose value shall be retrieved
2286         * @throws Exception if the given object is either invalid, or if the object
2287         *         is not a floating point based type.
2288         */
2289        double Archive::valueAsReal(const Object& object) {
2290            if (!object)
2291                throw Exception("Invalid object");
2292            if (!object.type().isReal())
2293                throw Exception("Object is not an real type");
2294            const Object* pObject = &object;
2295            if (object.type().isPointer()) {
2296                const Object& obj = objectByUID(object.uid(1));
2297                if (!obj) return 0;
2298                pObject = &obj;
2299            }
2300            return _primitiveObjectValueToNumber<double>(*pObject);
2301        }
2302    
2303        /** @brief Get boolean value of object.
2304         *
2305         * Returns the current boolean value of the requested boolean @a object.
2306         *
2307         * @param object - object whose value shall be retrieved
2308         * @throws Exception if the given object is either invalid, or if the object
2309         *         is not a boolean data type.
2310         */
2311        bool Archive::valueAsBool(const Object& object) {
2312            if (!object)
2313                throw Exception("Invalid object");
2314            if (!object.type().isBool())
2315                throw Exception("Object is not a bool");
2316            const Object* pObject = &object;
2317            if (object.type().isPointer()) {
2318                const Object& obj = objectByUID(object.uid(1));
2319                if (!obj) return 0;
2320                pObject = &obj;
2321            }
2322            return _primitiveObjectValueToNumber<bool>(*pObject);
2323        }
2324    
2325        Archive::operation_t Archive::operation() const {
2326            return m_operation;
2327        }
2328    
2329      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2330      // *      // *
2331    
# Line 915  namespace Serialization { Line 2347  namespace Serialization {
2347          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2348      }      }
2349    
2350        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2351            assert(dstObj.type().isString());
2352            assert(dstObj.type() == srcObj.type());
2353            String* pDst = (String*)(void*)dstObj.uid().id;
2354            *pDst = (String) (const char*) &srcObj.rawData()[0];
2355        }
2356    
2357      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2358          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2359          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 941  namespace Serialization { Line 2380  namespace Serialization {
2380          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2381    
2382          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2383              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2384                    syncString(dstObj, srcObj);
2385                else
2386                    syncPrimitive(dstObj, srcObj);
2387              return; // end of recursion              return; // end of recursion
2388          }          }
2389    
# Line 993  namespace Serialization { Line 2435  namespace Serialization {
2435      // *************** Exception ***************      // *************** Exception ***************
2436      // *      // *
2437    
2438        Exception::Exception() {
2439        }
2440    
2441        Exception::Exception(String format, ...) {
2442            va_list arg;
2443            va_start(arg, format);
2444            Message = assemble(format, arg);
2445            va_end(arg);
2446        }
2447    
2448        Exception::Exception(String format, va_list arg) {
2449            Message = assemble(format, arg);
2450        }
2451    
2452        /** @brief Print exception message to stdout.
2453         *
2454         * Prints the message of this Exception to the currently defined standard
2455         * output (that is to the terminal console for example).
2456         */
2457      void Exception::PrintMessage() {      void Exception::PrintMessage() {
2458          std::cout << "Serialization::Exception: " << Message << std::endl;          std::cout << "Serialization::Exception: " << Message << std::endl;
2459      }      }
2460    
2461        String Exception::assemble(String format, va_list arg) {
2462            char* buf = NULL;
2463            vasprintf(&buf, format.c_str(), arg);
2464            String s = buf;
2465            free(buf);
2466            return s;
2467        }
2468    
2469  } // namespace Serialization  } // namespace Serialization

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

  ViewVC Help
Powered by ViewVC