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

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

  ViewVC Help
Powered by ViewVC