/[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 3173 by schoenebeck, Wed May 10 23:07:28 2017 UTC revision 3775 by schoenebeck, Tue May 19 15:23:11 2020 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2017 Christian Schoenebeck                              *   *   Copyright (C) 2017-2020 Christian Schoenebeck                         *
4   *                      <cuse@users.sourceforge.net>                       *   *                           <cuse@users.sourceforge.net>                  *
5   *                                                                         *   *                                                                         *
6   *   This library is part of libgig.                                       *   *   This library is part of libgig.                                       *
7   *                                                                         *   *                                                                         *
# Line 21  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    // enable implementation specific declarations in Serialization.h required to
25    // build this C++ unit, which should be ignored in the public API though
26    #define LIBGIG_SERIALIZATION_INTERNAL 1
27    
28  #include "Serialization.h"  #include "Serialization.h"
29    
30  #include <iostream>  #include <iostream>
 #include <assert.h>  
31  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
32  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
33  #include <cxxabi.h>  #ifdef _MSC_VER
34    # include <windows.h>
35    # include <dbghelp.h>
36    #else
37    # include <cxxabi.h>
38    #endif
39  #include "helper.h"  #include "helper.h"
40    
41  #define LIBGIG_EPOCH_TIME ((time_t)0)  #define LIBGIG_EPOCH_TIME ((time_t)0)
# Line 45  namespace Serialization { Line 52  namespace Serialization {
52    
53      const UID NO_UID = _createNullUID();      const UID NO_UID = _createNullUID();
54    
55        /** @brief Check whether this is a valid unique identifier.
56         *
57         * Returns @c false if this UID can be considered an invalid unique
58         * identifier. This is for example the case if this UID object was not
59         * explicitly set to some certain meaningful unique identifier value, or if
60         * this UID object was intentionally assigned the constant @c NO_UID value.
61         * Both represent essentially an UID object which is all zero.
62         *
63         * Note that this class also implements the @c bool operator, both return
64         * the same boolean result.
65         */
66      bool UID::isValid() const {      bool UID::isValid() const {
67          return id != NULL && id != (void*)-1 && size;          return id != NULL && id != (void*)-1 && size;
68      }      }
# Line 52  namespace Serialization { Line 70  namespace Serialization {
70      // *************** DataType ***************      // *************** DataType ***************
71      // *      // *
72    
73        /** @brief Default constructor (as "invalid" DataType).
74         *
75         * Initializes a DataType object as being an "invalid" DataType object.
76         * Thus calling isValid(), after creating a DataType object with this
77         * constructor, would return @c false.
78         *
79         * To create a valid and meaningful DataType object instead, call the static
80         * function DataType::dataTypeOf() instead.
81         */
82      DataType::DataType() {      DataType::DataType() {
83          m_size = 0;          m_size = 0;
84          m_isPointer = false;          m_isPointer = false;
85      }      }
86    
87        /** @brief Constructs a valid DataType object.
88         *
89         * Initializes this object as "valid" DataType object, with specific and
90         * useful data type information.
91         *
92         * This is a protected constructor which should not be called directly by
93         * applications, as its argument list is somewhat implementation specific
94         * and might change at any time. Applications should call the static
95         * function DataType::dataTypeOf() instead.
96         *
97         * @param isPointer - whether pointer type (i.e. a simple memory address)
98         * @param size - native size of data type in bytes (i.e. according to
99         *               @c sizeof() C/C++ keyword)
100         * @param baseType - this framework's internal name for specifying the base
101         *                   type in a coarse way, which must be either one of:
102         *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",
103         *                   "int64", "uint64", "bool", "real32", "real64",
104         *                   "String", "Array", "enum", "union" or "class"
105         * @param customType - this is only used for base types "enum", "union",
106         *                     "class" or "Array", in which case this identifies the
107         *                     user defined type name (e.g. "Foo" for
108         *                     @c class @c Foo or e.g. "Bar" for @c Array<Bar>
109         *                     respectively), 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 64  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.
146         *
147         * @note: Data types which enjoy out of the box serialization support by
148         * this framework, like @c String and @c Array<> are @b NOT handled as class
149         * data types by this framwork. So @c isClass() returns @c false for e.g.
150         * @c String and any @c Array<> based data type.
151         *
152         * Note that in the following example:
153         * @code
154         * struct Foo {
155         *     int  a;
156         *     bool b;
157         * };
158         * Foo foo;
159         * Foo* pFoo;
160         * @endcode
161         * the DataType objects of both @c foo, as well as of the C/C++ pointer
162         * @c pFoo would both return @c true for isClass() here!
163         *
164         * @see isPointer()
165         */
166      bool DataType::isClass() const {      bool DataType::isClass() const {
167          return m_baseTypeName == "class";          return m_baseTypeName == "class";
168      }      }
169    
170        /** @brief Whether this is reflecting a fundamental C/C++ data type.
171         *
172         * Returns @c true if the respective native C/C++ object, member or variable
173         * (this DataType instance is reflecting) is a primitive, fundamental C/C++
174         * data type. Those are fundamental data types which are already predefined
175         * by the C/C++ language, for example: @c char, @c int, @c float, @c double,
176         * @c bool, but also @c String objects and @b any pointer types like
177         * @c int*, @c double**, but including pointers to user defined types like:
178         * @code
179         * struct Foo {
180         *     int  a;
181         *     bool b;
182         * };
183         * Foo* pFoo;
184         * @endcode
185         * So the DataType object of @c pFoo in the latter example would also return
186         * @c true for isPrimitive() here!
187         *
188         * @see isPointer()
189         */
190      bool DataType::isPrimitive() const {      bool DataType::isPrimitive() const {
191          return !isClass();          return !isClass() && !isArray();
192      }      }
193    
194        /** @brief Whether this is a C++ @c String data type.
195         *
196         * Returns @c true if the respective native C/C++ object, member or variable
197         * (this DataType instance is reflecting) is a C++ @c String object (a.k.a.
198         * @c std::string from the C++ STL).
199         *
200         * Note that this framework handles @c String objects as if they were a
201         * fundamental, primitive C/C++ data type, so @c isPrimitive() returns
202         * @c true for strings.
203         */
204        bool DataType::isString() const {
205            return m_baseTypeName == "String";
206        }
207    
208        /** @brief Whether this is an integer C/C++ data type.
209         *
210         * Returns @c true if the respective native C/C++ object, member or variable
211         * (this DataType instance is reflecting) is a (fundamental, primitive)
212         * integer data type. So these are all @c int and @c unsigned @c int types
213         * of any size. It does not include floating point ("real") types though.
214         *
215         * You may use isSigned() to further check whether this data type allows
216         * negative numbers.
217         *
218         * Note that this method also returns @c true on integer pointer types!
219         *
220         * @see isPointer()
221         */
222      bool DataType::isInteger() const {      bool DataType::isInteger() const {
223          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
224                 m_baseTypeName.substr(0, 4) == "uint";                 m_baseTypeName.substr(0, 4) == "uint";
225      }      }
226    
227        /** @brief Whether this is a floating point based C/C++ data type.
228         *
229         * Returns @c true if the respective native C/C++ object, member or variable
230         * (this DataType instance is reflecting) is a (fundamental, primitive)
231         * floating point based data type. So these are currently the C/C++ @c float
232         * and @c double types. It does not include integer types though.
233         *
234         * Note that this method also returns @c true on @c float pointer and
235         * @c double pointer types!
236         *
237         * @see isPointer()
238         */
239      bool DataType::isReal() const {      bool DataType::isReal() const {
240          return m_baseTypeName.substr(0, 4) == "real";          return m_baseTypeName.substr(0, 4) == "real";
241      }      }
242    
243        /** @brief Whether this is a boolean C/C++ data type.
244         *
245         * Returns @c true if the respective native C/C++ object, member or variable
246         * (this DataType instance is reflecting) is a (fundamental, primitive)
247         * boolean data type. So this is the case for the C++ @c bool data type.
248         * It does not include integer or floating point types though.
249         *
250         * Note that this method also returns @c true on @c bool pointer types!
251         *
252         * @see isPointer()
253         */
254      bool DataType::isBool() const {      bool DataType::isBool() const {
255          return m_baseTypeName == "bool";          return m_baseTypeName == "bool";
256      }      }
257    
258        /** @brief Whether this is a C/C++ @c enum data type.
259         *
260         * Returns @c true if the respective native C/C++ object, member or variable
261         * (this DataType instance is reflecting) is a user defined enumeration
262         * data type. So this is the case for all C/C++ @c enum data types.
263         * It does not include integer (or even floating point) types though.
264         *
265         * Note that this method also returns @c true on @c enum pointer types!
266         *
267         * @see isPointer()
268         */
269      bool DataType::isEnum() const {      bool DataType::isEnum() const {
270          return m_baseTypeName == "enum";          return m_baseTypeName == "enum";
271      }      }
272    
273        /** @brief Whether this is a C++ @c Array<> object type.
274         *
275         * Returns @c true if the respective native C/C++ object, member or variable
276         * (this DataType instance is reflecting) is a C++ @c Array<> container
277         * object type.
278         *
279         * @note: This framework handles @c Array<> types neither as primitive
280         * types, nor as class types. So @c isPrimitive() and @c isClass() both
281         * return @c false for arrays.
282         *
283         * @see isPointer()
284         */
285        bool DataType::isArray() const {
286            return m_baseTypeName == "Array";
287        }
288    
289        /** @brief Whether this is a signed integer C/C++ data type.
290         *
291         * Returns @c true if the respective native C/C++ object, member or variable
292         * (this DataType instance is reflecting) is a (fundamental, primitive)
293         * signed integer data type. This is the case for are all @c unsigned
294         * @c int C/C++ types of any size. For all floating point ("real") based
295         * types this method returns @c false though!
296         *
297         * Note that this method also returns @c true on signed integer pointer
298         * types!
299         *
300         * @see isInteger();
301         */
302      bool DataType::isSigned() const {      bool DataType::isSigned() const {
303          return m_baseTypeName.substr(0, 3) == "int" ||          return m_baseTypeName.substr(0, 3) == "int" ||
304                 isReal();                 isReal();
305      }      }
306    
307        /** @brief Comparison for equalness.
308         *
309         * Returns @c true if the two DataType objects being compared can be
310         * considered to be "equal" C/C++ data types. They are considered to be
311         * equal if their underlying C/C++ data types are exactly identical. For
312         * example comparing @c int and @c unsigned int data types are considere to
313         * be @b not equal, since they are differently signed. Furthermore @c short
314         * @c int and @c long @c int would also not be considered to be equal, since
315         * they do have a different memory size. Additionally pointer type
316         * characteristic is compared as well. So a @c double type and @c double*
317         * type are also considered to be not equal data types and hence this method
318         * would return @c false.
319         *
320         * As an exception here, classes and structs with the same class/struct name
321         * but different sizes are also considered to be "equal". This relaxed
322         * requirement is necessary to retain backward compatiblity to older
323         * versions of the same native C++ classes/structs.
324         */
325      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
326          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
327                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
328                 m_size           == other.m_size &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
329                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
330      }      }
331    
332        /** @brief Comparison for inequalness.
333         *
334         * Returns the inverse result of what DataType::operator==() would return.
335         * So refer to the latter for more details.
336         */
337      bool DataType::operator!=(const DataType& other) const {      bool DataType::operator!=(const DataType& other) const {
338          return !operator==(other);          return !operator==(other);
339      }      }
340    
341        /** @brief Smaller than comparison.
342         *
343         * Returns @c true if this DataType object can be consider to be "smaller"
344         * than the @a other DataType object being compared with. This operator
345         * is actually quite arbitrarily implemented and may change at any time,
346         * and thus result for the same data types may change in future at any time.
347         *
348         * This operator is basically implemented for allowing this DataType class
349         * to be used with various standard template library (STL) classes, which
350         * require sorting operators to be implemented.
351         */
352      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
353          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
354                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
355                 m_customTypeName  < other.m_customTypeName ||                (m_customTypeName  < other.m_customTypeName ||
356                (m_customTypeName == other.m_customTypeName &&                (m_customTypeName == other.m_customTypeName &&
357                 m_size  < other.m_size ||                (m_size  < other.m_size ||
358                (m_size == other.m_size &&                (m_size == other.m_size &&
359                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)))));
360      }      }
361    
362        /** @brief Greater than comparison.
363         *
364         * Returns @c true if this DataType object can be consider to be "greater"
365         * than the @a other DataType object being compared with. This operator
366         * is actually quite arbitrarily implemented and may change at any time,
367         * and thus result for the same data types may change in future at any time.
368         *
369         * This operator is basically implemented for allowing this DataType class
370         * to be used with various standard template library (STL) classes, which
371         * require sorting operators to be implemented.
372         */
373      bool DataType::operator>(const DataType& other) const {      bool DataType::operator>(const DataType& other) const {
374          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
375      }      }
376    
377        /** @brief Human readable long description for this data type.
378         *
379         * Returns a human readable long description for this data type, designed
380         * for the purpose for being displayed to the user. Note that the
381         * implementation for this method and thus the precise textual strings
382         * returned by this method, may change at any time. So you should not rely
383         * on precise strings for certain data types, and you should not use the
384         * return values of this method for comparing data types with each other.
385         *
386         * This class implements various comparison operators, so you should use
387         * them for comparing DataTypes objects instead.
388         *
389         * @see baseTypeName(), customTypeName()
390         */
391      String DataType::asLongDescr() const {      String DataType::asLongDescr() const {
392          String s = m_baseTypeName;          String s = m_baseTypeName;
393          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
# Line 136  namespace Serialization { Line 397  namespace Serialization {
397          return s;          return s;
398      }      }
399    
400        /** @brief The base type name of this data type.
401         *
402         * Returns a textual short string identifying the basic type of name of this
403         * data type. For example for a 32 bit signed integer data type this method
404         * would return @c "int32". For all user defined C/C++ @c enum types this
405         * method would return "enum". For all user defined C/C++ @c struct @b and
406         * @c class types this method would return "class" for both. Note that the
407         * precise user defined type name (of i.e. @c enum, @c struct and @c class
408         * types) is not included in the string returned by this method, use
409         * customTypeName() to retrieve that information instead.
410         *
411         * The precise textual strings returned by this method are guaranteed to
412         * retain equal with future versions of this framework. So you can rely on
413         * them for using the return values of this method for comparison tasks in
414         * your application. Note however that this class also implements various
415         * comparison operators.
416         *
417         * Further it is important to know that this method returns the same string
418         * for pointers and non-pointers of the same underlying data type. So in the
419         * following example:
420         * @code
421         * #include <stdint.h>
422         * uint64_t i;
423         * uint64_t* pi;
424         * @endcode
425         * this method would return for both @c i and @c pi the string @c "uint64" !
426         *
427         * @see isPointer(), customTypeName()
428         */
429        String DataType::baseTypeName() const {
430            return m_baseTypeName;
431        }
432    
433        /** @brief The user defined C/C++ data type name of this data type.
434         *
435         * Call this method on user defined C/C++ data types like @c enum,
436         * @c struct, @c class or @c Array<> types to retrieve the user defined type
437         * name portion of those data types. Note that this method is only intended
438         * for such user defined data types. For all fundamental, primitive data
439         * types (like i.e. @c int) this method returns an empty string instead.
440         *
441         * This method takes an optional boolean argument @b demangle, which allows
442         * you define whether you are interested in the raw C++ type name or rather
443         * the demangled custom type name. By default this method returns the raw
444         * C++ type name. The raw C++ type name is the one that is actually used
445         * in the compiled binaries and should be preferred for comparions tasks.
446         * The demangled C++ type name is a human readable representation of the
447         * type name instead, which you may use for displaying the user defined type
448         * name portion to the user, however you should not use the demangled
449         * representation for comparison tasks.
450         *
451         * Note that in the following example:
452         * @code
453         * struct Foo {
454         *     int  a;
455         *     bool b;
456         * };
457         * Foo foo;
458         * Foo* pFoo;
459         * @endcode
460         * this method would return the same string for both @c foo and @c pFoo !
461         * In the latter example @c customTypeName(true) would return for both
462         * @c foo and @c pFoo the string @c "Foo" as return value of this method.
463         *
464         * @b Windows: please note that the current implementation of this method
465         * on Windows is @b not thread safe!
466         *
467         * @see isPointer(), baseTypeName()
468         */
469      String DataType::customTypeName(bool demangle) const {      String DataType::customTypeName(bool demangle) const {
470          if (!demangle) return m_customTypeName;          if (!demangle) return m_customTypeName;
471    #ifdef _MSC_VER
472            const size_t MAXLENGTH = 1024;
473            char result[MAXLENGTH];
474    
475            //FIXME: calling UnDecorateSymbolName() is not thread safe!
476            //Skip the first char
477            size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
478            if (size)
479            {
480                return result;
481            }
482            return m_customTypeName;
483    #else
484          int status;          int status;
485          const char* result =          char* result =
486              abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);              abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
487          return (status == 0) ? result : m_customTypeName;          String sResult = result;
488            free(result);
489            return (status == 0) ? sResult : m_customTypeName;
490    #endif
491      }      }
492    
493      // *************** Member ***************      // *************** Member ***************
494      // *      // *
495    
496        /** @brief Default constructor.
497         *
498         * Initializes a Member object as being an "invalid" Member object.
499         * Thus calling isValid(), after creating a Member object with this
500         * constructor, would return @c false.
501         *
502         * You are currently not supposed to create (meaningful) Member objects on
503         * your own. This framework automatically create such Member objects for
504         * you instead.
505         *
506         * @see Object::members()
507         */
508      Member::Member() {      Member::Member() {
509          m_uid = NO_UID;          m_uid = NO_UID;
510          m_offset = 0;          m_offset = 0;
511      }      }
512    
513      Member::Member(String name, UID uid, size_t offset, DataType type) {      Member::Member(String name, UID uid, ssize_t offset, DataType type) {
514          m_name = name;          m_name = name;
515          m_uid  = uid;          m_uid  = uid;
516          m_offset = offset;          m_offset = offset;
517          m_type = type;          m_type = type;
518      }      }
519    
520        /** @brief Unique identifier of this member instance.
521         *
522         * Returns the unique identifier of the original C/C++ member instance of
523         * your C++ class. It is important to know that this unique identifier is
524         * not meant to be unique for Member instances themselves, but it is rather
525         * meant to be unique for the original native C/C++ data these Member
526         * instances are representing. So that means no matter how many individual
527         * Member objects are created, as long as they are representing the same
528         * original native member variable of the same original native
529         * instance of your C++ class, then all those separately created Member
530         * objects return the same unique identifier here.
531         *
532         * @see UID for more details
533         */
534        UID Member::uid() const {
535            return m_uid;
536        }
537    
538        /** @brief Name of the member.
539         *
540         * Returns the name of the native C/C++ member variable as originally typed
541         * in its C++ source code. So in the following example:
542         * @code
543         * struct Foo {
544         *     int  a;
545         *     bool b;
546         *     double someValue;
547         * };
548         * @endcode
549         * this method would usually return @c "a" for the first member of object
550         * instances of your native C/C++ @c struct @c Foo, and this method would
551         * usually return @c "someValue" for its third member.
552         *
553         * Note that when you implement the @c serialize() method of your own C/C++
554         * clases or strucs, you are able to override defining the precise name of
555         * your members. In that case this method would of course return the member
556         * names as explicitly forced by you instead.
557         */
558        String Member::name() const {
559            return m_name;
560        }
561    
562        /** @brief Offset of member in its containing parent data structure.
563         *
564         * Returns the offset of this member (in bytes) within its containing parent
565         * user defined data structure or class. So in the following example:
566         * @code
567         * #include <stdint.h>
568         * struct Foo __attribute__ ((__packed__)) {
569         *     int32_t a;
570         *     bool b;
571         *     double c;
572         * };
573         * @endcode
574         * this method would typically return @c 0 for member @c a, @c 4 for member
575         * @c b and @c 5 for member @c c. As you have noted in the latter example,
576         * the structure @c Foo was declared to have "packed" data members. That
577         * means the compiler is instructed to add no memory spaces between the
578         * individual members. Because by default the compiler might add memory
579         * spaces between individual members to align them on certain memory address
580         * boundaries for increasing runtime performance while accessing the
581         * members. So if you declared the previous example without the "packed"
582         * attribute like:
583         * @code
584         * #include <stdint.h>
585         * struct Foo {
586         *     int32_t a;
587         *     bool b;
588         *     double c;
589         * };
590         * @endcode
591         * then this method would usually return a different offset for members
592         * @c b and @c c instead. For most 64 bit architectures this example would
593         * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
594         * for member @c c.
595         *
596         * @note Offset is intended for native members only, that is member
597         * variables which are memory located directly within the associated parent
598         * data structure. For members allocated on the heap @c offset() always
599         * returns @c -1 instead since there is no constant, static offset
600         * relationship between data on the heap and the parent structure owning
601         * their life-time control.
602         */
603        ssize_t Member::offset() const {
604            return m_offset;
605        }
606    
607        /** @brief C/C++ Data type of this member.
608         *
609         * Returns the precise data type of the original native C/C++ member.
610         */
611        const DataType& Member::type() const {
612            return m_type;
613        }
614    
615        /** @brief Check if this is a valid Member object.
616         *
617         * Returns @c true if this Member object is reflecting a "valid" member
618         * object. The default constructor creates Member objects initialized to be
619         * "invalid" Member objects by default. That way one can detect whether
620         * a Member object was ever assigned to something meaningful.
621         *
622         * Note that this class also implements the @c bool operator, both return
623         * the same boolean result value.
624         */
625      bool Member::isValid() const {      bool Member::isValid() const {
626          return m_uid && !m_name.empty() && m_type;          return m_uid && !m_name.empty() && m_type;
627      }      }
628    
629        /** @brief Comparison for equalness.
630         *
631         * Returns @c true if the two Member objects being compared can be
632         * considered to be "equal" C/C++ members. They are considered to be
633         * equal if their data type, member name, their offset within their parent
634         * containing C/C++ data structure, as well as their original native C/C++
635         * instance were exactly identical.
636         */
637      bool Member::operator==(const Member& other) const {      bool Member::operator==(const Member& other) const {
638          return m_uid    == other.m_uid &&          return m_uid    == other.m_uid &&
639                 m_offset == other.m_offset &&                 m_offset == other.m_offset &&
# Line 170  namespace Serialization { Line 641  namespace Serialization {
641                 m_type   == other.m_type;                 m_type   == other.m_type;
642      }      }
643    
644        /** @brief Comparison for inequalness.
645         *
646         * Returns the inverse result of what Member::operator==() would return.
647         * So refer to the latter for more details.
648         */
649      bool Member::operator!=(const Member& other) const {      bool Member::operator!=(const Member& other) const {
650          return !operator==(other);          return !operator==(other);
651      }      }
652    
653        /** @brief Smaller than comparison.
654         *
655         * Returns @c true if this Member object can be consider to be "smaller"
656         * than the @a other Member object being compared with. This operator
657         * is actually quite arbitrarily implemented and may change at any time,
658         * and thus result for the same member representations may change in
659         * future at any time.
660         *
661         * This operator is basically implemented for allowing this DataType class
662         * to be used with various standard template library (STL) classes, which
663         * require sorting operators to be implemented.
664         */
665      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
666          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
667                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
668                 m_offset  < other.m_offset ||                (m_offset  < other.m_offset ||
669                (m_offset == other.m_offset &&                (m_offset == other.m_offset &&
670                 m_name  < other.m_name ||                (m_name  < other.m_name ||
671                (m_name == other.m_name &&                (m_name == other.m_name &&
672                 m_type < other.m_type)));                 m_type < other.m_type)))));
673      }      }
674    
675        /** @brief Greater than comparison.
676         *
677         * Returns @c true if this Member object can be consider to be "greater"
678         * than the @a other Member object being compared with. This operator
679         * is actually quite arbitrarily implemented and may change at any time,
680         * and thus result for the same member representations may change in
681         * future at any time.
682         *
683         * This operator is basically implemented for allowing this DataType class
684         * to be used with various standard template library (STL) classes, which
685         * require sorting operators to be implemented.
686         */
687      bool Member::operator>(const Member& other) const {      bool Member::operator>(const Member& other) const {
688          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
689      }      }
# Line 191  namespace Serialization { Line 691  namespace Serialization {
691      // *************** Object ***************      // *************** Object ***************
692      // *      // *
693    
694        /** @brief Default constructor (for an "invalid" Object).
695         *
696         * Initializes an Object instance as being an "invalid" Object.
697         * Thus calling isValid(), after creating an Object instance with this
698         * constructor, would return @c false.
699         *
700         * Usually you are not supposed to create (meaningful) Object instances on
701         * your own. They are typically constructed by the Archive class for you.
702         *
703         * @see Archive::rootObject(), Archive::objectByUID()
704         */
705      Object::Object() {      Object::Object() {
706          m_version = 0;          m_version = 0;
707          m_minVersion = 0;          m_minVersion = 0;
708      }      }
709    
710        /** @brief Constructor for a "meaningful" Object.
711         *
712         * Initializes a "meaningful" Object instance as being. Thus calling
713         * isValid(), after creating an Object instance with this constructor,
714         * should return @c true, provided that the arguments passed to this
715         * constructor construe a valid object representation.
716         *
717         * Usually you are not supposed to create (meaningful) Object instances on
718         * your own. They are typically constructed by the Archive class for you.
719         *
720         * @see Archive::rootObject(), Archive::objectByUID()
721         *
722         * @param uidChain - unique identifier chain of the object to be constructed
723         * @param type - C/C++ data type of the actual native object this abstract
724         *               Object instance should reflect after calling this
725         *               constructor
726         */
727      Object::Object(UIDChain uidChain, DataType type) {      Object::Object(UIDChain uidChain, DataType type) {
728          m_type = type;          m_type = type;
729          m_uid  = uidChain;          m_uid  = uidChain;
# Line 204  namespace Serialization { Line 732  namespace Serialization {
732          //m_data.resize(type.size());          //m_data.resize(type.size());
733      }      }
734    
735        /** @brief Check if this is a valid Object instance.
736         *
737         * Returns @c true if this Object instance is reflecting a "valid" Object.
738         * The default constructor creates Object instances initialized to be
739         * "invalid" Objects by default. That way one can detect whether an Object
740         * instance was ever assigned to something meaningful.
741         *
742         * Note that this class also implements the @c bool operator, both return
743         * the same boolean result value.
744         */
745      bool Object::isValid() const {      bool Object::isValid() const {
746          return m_type && !m_uid.empty();          return m_type && !m_uid.empty();
747      }      }
748    
749        /** @brief Unique identifier of this Object.
750         *
751         * Returns the unique identifier for the original native C/C++ data this
752         * abstract Object instance is reflecting. If this Object is representing
753         * a C/C++ pointer (of first degree) then @c uid() (or @c uid(0) ) returns
754         * the unique identifier of the pointer itself, whereas @c uid(1) returns
755         * the unique identifier of the original C/C++ data that pointer was
756         * actually pointing to.
757         *
758         * @see UIDChain for more details about this overall topic.
759         */
760        UID Object::uid(int index) const {
761            return (index < m_uid.size()) ? m_uid[index] : NO_UID;
762        }
763    
764        /** @brief Unique identifier chain of this Object.
765         *
766         * Returns the entire unique identifier chain of this Object.
767         *
768         * @see uid() and UIDChain for more details about this overall topic.
769         */
770        const UIDChain& Object::uidChain() const {
771            return m_uid;
772        }
773    
774        /** @brief C/C++ data type this Object is reflecting.
775         *
776         * Returns the precise original C/C++ data type of the original native
777         * C/C++ object or data this Object instance is reflecting.
778         */
779        const DataType& Object::type() const {
780            return m_type;
781        }
782    
783        /** @brief Raw data of the original native C/C++ data.
784         *
785         * Returns the raw data value of the original C/C++ data this Object is
786         * reflecting. So the precise raw data value, layout and size is dependent
787         * to the precise C/C++ data type of the original native C/C++ data. However
788         * potentially required endian correction is already automatically applied
789         * for you. That means you can safely, directly C-cast the raw data returned
790         * by this method to the respective native C/C++ data type in order to
791         * access and use the value for some purpose, at least if the respective
792         * data is of any fundamental, primitive C/C++ data type, or also to a
793         * certain extent if the type is user defined @c enum type.
794         *
795         * However directly C-casting this raw data for user defined @c struct or
796         * @c class types is not possible. For those user defined data structures
797         * this method always returns empty raw data instead.
798         *
799         * Note however that there are more convenient methods in the Archive class
800         * to get the right value for the individual data types instead.
801         *
802         * @see Archive::valueAsInt(), Archive::valueAsReal(), Archive::valueAsBool(),
803         *      Archive::valueAsString()
804         */
805        const RawData& Object::rawData() const {
806            return m_data;
807        }
808    
809        /** @brief Version of original user defined C/C++ @c struct or @c class.
810         *
811         * In case this Object is reflecting a native C/C++ @c struct or @c class
812         * type, then this method returns the version of that native C/C++ @c struct
813         * or @c class layout or implementation. For primitive, fundamental C/C++
814         * data types (including @c String objects) the return value of this method
815         * has no meaning.
816         *
817         * @see Archive::setVersion() for more details about this overall topic.
818         */
819        Version Object::version() const {
820            return m_version;
821        }
822    
823        /** @brief Minimum version of original user defined C/C++ @c struct or @c class.
824         *
825         * In case this Object is reflecting a native C/C++ @c struct or @c class
826         * type, then this method returns the "minimum" version of that native C/C++
827         * @c struct or @c class layout or implementation which it may be compatible
828         * with. For primitive, fundamental C/C++ data types (including @c String
829         * objects) the return value of this method has no meaning.
830         *
831         * @see Archive::setVersion() and Archive::setMinVersion() for more details
832         *      about this overall topic.
833         */
834        Version Object::minVersion() const {
835            return m_minVersion;
836        }
837    
838        /** @brief All members of the original native C/C++ @c struct or @c class instance.
839         *
840         * In case this Object is reflecting a native C/C++ @c struct or @c class
841         * type, then this method returns all member variables of that original
842         * native C/C++ @c struct or @c class instance. For primitive, fundamental
843         * C/C++ data types this method returns an empty vector instead.
844         *
845         * Example:
846         * @code
847         * struct Foo {
848         *     int  a;
849         *     bool b;
850         *     double someValue;
851         * };
852         * @endcode
853         * Considering above's C++ code, a serialized Object representation of such
854         * a native @c Foo class would have 3 members @c a, @c b and @c someValue.
855         *
856         * Note that the respective serialize() method implementation of that
857         * fictional C++ @c struct @c Foo actually defines which members are going
858         * to be serialized and deserialized for instances of class @c Foo. So in
859         * practice the members returned by method members() here might return a
860         * different set of members as actually defined in the original C/C++ struct
861         * header declaration.
862         *
863         * The precise sequence of the members returned by this method here depends
864         * on the actual serialize() implementation of the user defined C/C++
865         * @c struct or @c class.
866         *
867         * @see Object::sequenceIndexOf() for more details about the precise order
868         *      of members returned by this method in the same way.
869         */
870        std::vector<Member>& Object::members() {
871            return m_members;
872        }
873    
874        /** @brief All members of the original native C/C++ @c struct or @c class instance (read only).
875         *
876         * Returns the same result as overridden members() method above, it just
877         * returns a read-only result instead. See above's method description for
878         * details for the return value of this method instead.
879         */
880        const std::vector<Member>& Object::members() const {
881            return m_members;
882        }
883    
884        /** @brief Comparison for equalness.
885         *
886         * Returns @c true if the two Object instances being compared can be
887         * considered to be "equal" native C/C++ object instances. They are
888         * considered to be equal if they are representing the same original
889         * C/C++ data instance, which is essentially the case if the original
890         * reflecting native C/C++ data are sharing the same memory address and
891         * memory size (thus the exact same memory space) and originally had the
892         * exact same native C/C++ types.
893         */
894      bool Object::operator==(const Object& other) const {      bool Object::operator==(const Object& other) const {
895          // ignoring all other member variables here          // ignoring all other member variables here
896          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 215  namespace Serialization { Line 898  namespace Serialization {
898                 m_type == other.m_type;                 m_type == other.m_type;
899      }      }
900    
901        /** @brief Comparison for inequalness.
902         *
903         * Returns the inverse result of what Object::operator==() would return.
904         * So refer to the latter for more details.
905         */
906      bool Object::operator!=(const Object& other) const {      bool Object::operator!=(const Object& other) const {
907          return !operator==(other);          return !operator==(other);
908      }      }
909    
910        /** @brief Smaller than comparison.
911         *
912         * Returns @c true if this Object instance can be consider to be "smaller"
913         * than the @a other Object instance being compared with. This operator
914         * is actually quite arbitrarily implemented and may change at any time,
915         * and thus result for the same Object representations may change in future
916         * at any time.
917         *
918         * This operator is basically implemented for allowing this DataType class
919         * to be used with various standard template library (STL) classes, which
920         * require sorting operators to be implemented.
921         */
922      bool Object::operator<(const Object& other) const {      bool Object::operator<(const Object& other) const {
923          // ignoring all other member variables here          // ignoring all other member variables here
924          // (since UID stands for "unique" ;-) )          // (since UID stands for "unique" ;-) )
# Line 227  namespace Serialization { Line 927  namespace Serialization {
927                 m_type < other.m_type);                 m_type < other.m_type);
928      }      }
929    
930        /** @brief Greater than comparison.
931         *
932         * Returns @c true if this Object instance can be consider to be "greater"
933         * than the @a other Object instance being compared with. This operator
934         * is actually quite arbitrarily implemented and may change at any time,
935         * and thus result for the same Object representations may change in future
936         * at any time.
937         *
938         * This operator is basically implemented for allowing this DataType class
939         * to be used with various standard template library (STL) classes, which
940         * require sorting operators to be implemented.
941         */
942      bool Object::operator>(const Object& other) const {      bool Object::operator>(const Object& other) const {
943          return !(operator==(other) || operator<(other));          return !(operator==(other) || operator<(other));
944      }      }
945    
946        /** @brief Check version compatibility between Object instances.
947         *
948         * Use this method to check whether the two original C/C++ instances those
949         * two Objects are reflecting, were using a C/C++ data type which are version
950         * compatible with each other. By default all C/C++ Objects are considered
951         * to be version compatible. They might only be version incompatible if you
952         * enforced a certain backward compatibility constraint with your
953         * serialize() method implementation of your custom C/C++ @c struct or
954         * @c class types.
955         *
956         * You must only call this method on two Object instances which are
957         * representing the same data type, for example if both Objects reflect
958         * instances of the same user defined C++ class. Calling this method on
959         * completely different data types does not cause an error or exception, but
960         * its result would simply be useless for any purpose.
961         *
962         * @see Archive::setVersion() for more details about this overall topic.
963         */
964      bool Object::isVersionCompatibleTo(const Object& other) const {      bool Object::isVersionCompatibleTo(const Object& other) const {
965          if (this->version() == other.version())          if (this->version() == other.version())
966              return true;              return true;
# Line 240  namespace Serialization { Line 970  namespace Serialization {
970              return other.minVersion() <= this->version();              return other.minVersion() <= this->version();
971      }      }
972    
973        void Object::setVersion(Version v) {
974            m_version = v;
975        }
976    
977        void Object::setMinVersion(Version v) {
978            m_minVersion = v;
979        }
980    
981        /** @brief Get the member of this Object with given name.
982         *
983         * In case this Object is reflecting a native C/C++ @c struct or @c class
984         * type, then this method returns the abstract reflection of the requested
985         * member variable of the original native C/C++ @c struct or @c class
986         * instance. For primitive, fundamental C/C++ data types this method always
987         * returns an "invalid" Member instance instead.
988         *
989         * Example:
990         * @code
991         * struct Foo {
992         *     int  a;
993         *     bool b;
994         *     double someValue;
995         * };
996         * @endcode
997         * Consider that you serialized the native C/C++ @c struct as shown in this
998         * example, and assuming that you implemented the respective serialize()
999         * method of this C++ @c struct to serialize all its members, then you might
1000         * call memberNamed("someValue") to get the details of the third member in
1001         * this example for instance. In case the passed @a name is an unknown
1002         * member name, then this method will return an "invalid" Member object
1003         * instead.
1004         *
1005         * @param name - original name of the sought serialized member variable of
1006         *               this Object reflection
1007         * @returns abstract reflection of the sought member variable
1008         * @see Member::isValid(), Object::members()
1009         */
1010      Member Object::memberNamed(String name) const {      Member Object::memberNamed(String name) const {
1011          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
1012              if (m_members[i].name() == name)              if (m_members[i].name() == name)
# Line 247  namespace Serialization { Line 1014  namespace Serialization {
1014          return Member();          return Member();
1015      }      }
1016    
1017        /** @brief Get the member of this Object with given unique identifier.
1018         *
1019         * This method behaves similar like method memberNamed() described above,
1020         * but instead of searching for a member variable by name, it searches for
1021         * a member with an abstract unique identifier instead. For primitive,
1022         * fundamental C/C++ data types, for invalid or unknown unique identifiers,
1023         * and for members which are actually not member instances of the original
1024         * C/C++ @c struct or @c class instance this Object is reflecting, this
1025         * method returns an "invalid" Member instance instead.
1026         *
1027         * @param uid - unique identifier of the member variable being sought
1028         * @returns abstract reflection of the sought member variable
1029         * @see Member::isValid(), Object::members(), Object::memberNamed()
1030         */
1031      Member Object::memberByUID(const UID& uid) const {      Member Object::memberByUID(const UID& uid) const {
1032          if (!uid) return Member();          if (!uid) return Member();
1033          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
# Line 264  namespace Serialization { Line 1045  namespace Serialization {
1045          }          }
1046      }      }
1047    
1048        /** @brief Get all members of this Object with given data type.
1049         *
1050         * In case this Object is reflecting a native C/C++ @c struct or @c class
1051         * type, then this method returns all member variables of that original
1052         * native C/C++ @c struct or @c class instance which are matching the given
1053         * requested data @a type. If this Object is reflecting a primitive,
1054         * fundamental data type, or if there are no members of this Object with the
1055         * requested precise C/C++ data type, then this method returns an empty
1056         * vector instead.
1057         *
1058         * @param type - the precise C/C++ data type of the sought member variables
1059         *               of this Object
1060         * @returns vector with abstract reflections of the sought member variables
1061         * @see Object::members(), Object::memberNamed()
1062         */
1063      std::vector<Member> Object::membersOfType(const DataType& type) const {      std::vector<Member> Object::membersOfType(const DataType& type) const {
1064          std::vector<Member> v;          std::vector<Member> v;
1065          for (int i = 0; i < m_members.size(); ++i) {          for (int i = 0; i < m_members.size(); ++i) {
# Line 274  namespace Serialization { Line 1070  namespace Serialization {
1070          return v;          return v;
1071      }      }
1072    
1073        /** @brief Serialization/deserialization sequence number of the requested member.
1074         *
1075         * Returns the precise serialization/deserialization sequence number of the
1076         * requested @a member variable.
1077         *
1078         * Example:
1079         * @code
1080         * struct Foo {
1081         *     int  a;
1082         *     bool b;
1083         *     double c;
1084         *
1085         *     void serialize(Serialization::Archive* archive);
1086         * };
1087         * @endcode
1088         * Assuming the declaration of the user defined native C/C++ @c struct
1089         * @c Foo above, and assuming the following implementation of serialize():
1090         * @code
1091         * #define SRLZ(member) \
1092         *   archive->serializeMember(*this, member, #member);
1093         *
1094         * void Foo::serialize(Serialization::Archive* archive) {
1095         *     SRLZ(c);
1096         *     SRLZ(a);
1097         *     SRLZ(b);
1098         * }
1099         * @endcode
1100         * then @c sequenceIndexOf(obj.memberNamed("a")) returns 1,
1101         * @c sequenceIndexOf(obj.memberNamed("b")) returns 2, and
1102         * @c sequenceIndexOf(obj.memberNamed("c")) returns 0.
1103         */
1104      int Object::sequenceIndexOf(const Member& member) const {      int Object::sequenceIndexOf(const Member& member) const {
1105          for (int i = 0; i < m_members.size(); ++i)          for (int i = 0; i < m_members.size(); ++i)
1106              if (m_members[i] == member)              if (m_members[i] == member)
# Line 284  namespace Serialization { Line 1111  namespace Serialization {
1111      // *************** Archive ***************      // *************** Archive ***************
1112      // *      // *
1113    
1114        /** @brief Create an "empty" archive.
1115         *
1116         * This default constructor creates an "empty" archive which you then
1117         * subsequently for example might fill with serialized data like:
1118         * @code
1119         * Archive a;
1120         * a.serialize(&myRootObject);
1121         * @endcode
1122         * Or:
1123         * @code
1124         * Archive a;
1125         * a << myRootObject;
1126         * @endcode
1127         * Or you might also subsequently assign an already existing non-empty
1128         * to this empty archive, which effectively clones the other
1129         * archive (deep copy) or call decode() later on to assign a previously
1130         * serialized raw data stream.
1131         */
1132      Archive::Archive() {      Archive::Archive() {
1133          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1134          m_root = NO_UID;          m_root = NO_UID;
# Line 291  namespace Serialization { Line 1136  namespace Serialization {
1136          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1137      }      }
1138    
1139        /** @brief Create and fill the archive with the given serialized raw data.
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         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1152         *         incompatible or corrupt data stream or format.
1153         */
1154      Archive::Archive(const RawData& data) {      Archive::Archive(const RawData& data) {
1155          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1156          m_root = NO_UID;          m_root = NO_UID;
1157          m_isModified = false;          m_isModified = false;
1158          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1159          decode(m_rawData);          decode(data);
1160      }      }
1161    
1162        /** @brief Create and fill the archive with the given serialized raw C-buffer data.
1163         *
1164         * This constructor essentially works like the constructor above, but just
1165         * uses another data type for the serialized raw data stream being passed to
1166         * this class.
1167         *
1168         * This constructor decodes the given raw @a data and constructs a
1169         * (non-empty) Archive object according to that given serialized data
1170         * stream.
1171         *
1172         * After this constructor returned, you may then traverse the individual
1173         * objects by starting with accessing the rootObject() for example. Finally
1174         * you might call deserialize() to restore your native C++ objects with the
1175         * content of this archive.
1176         *
1177         * @param data - the previously serialized raw data stream to be decoded
1178         * @param size - size of @a data in bytes
1179         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1180         *         incompatible or corrupt data stream or format.
1181         */
1182      Archive::Archive(const uint8_t* data, size_t size) {      Archive::Archive(const uint8_t* data, size_t size) {
1183          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
1184          m_root = NO_UID;          m_root = NO_UID;
# Line 310  namespace Serialization { Line 1190  namespace Serialization {
1190      Archive::~Archive() {      Archive::~Archive() {
1191      }      }
1192    
1193        /** @brief Root C++ object of this archive.
1194         *
1195         * In case this is a non-empty Archive, then this method returns the so
1196         * called "root" C++ object. If this is an empty archive, then this method
1197         * returns an "invalid" Object instance instead.
1198         *
1199         * @see Archive::serialize() for more details about the "root" object concept.
1200         * @see Object for more details about the overall object reflection concept.
1201         * @returns reflection of the original native C++ root object
1202         */
1203      Object& Archive::rootObject() {      Object& Archive::rootObject() {
1204          return m_allObjects[m_root];          return m_allObjects[m_root];
1205      }      }
# Line 402  namespace Serialization { Line 1292  namespace Serialization {
1292                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1293              } else if (type.isBool()) {              } else if (type.isBool()) {
1294                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1295                } else if (type.isString()) {
1296                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1297              } else {              } else {
1298                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1299              }              }
   
1300          }          }
1301          return s;          return s;
1302      }      }
1303    
1304      template<typename T>      template<typename T>
1305        inline T _stringToNumber(const String& s) {
1306            assert(false /* String cast to unknown primitive number type */);
1307        }
1308    
1309        template<>
1310        inline int64_t _stringToNumber(const String& s) {
1311            return atoll(s.c_str());
1312        }
1313    
1314        template<>
1315        inline double _stringToNumber(const String& s) {
1316            return atof(s.c_str());
1317        }
1318    
1319        template<>
1320        inline bool _stringToNumber(const String& s) {
1321            return (bool) atoll(s.c_str());
1322        }
1323    
1324        template<typename T>
1325      static T _primitiveObjectValueToNumber(const Object& obj) {      static T _primitiveObjectValueToNumber(const Object& obj) {
1326          T value = 0;          T value = 0;
1327          const DataType& type = obj.type();          const DataType& type = obj.type();
# Line 452  namespace Serialization { Line 1363  namespace Serialization {
1363                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1364              } else if (type.isBool()) {              } else if (type.isBool()) {
1365                  value = (T)*(bool*)ptr;                  value = (T)*(bool*)ptr;
1366                } else if (type.isString()) {
1367                    value = _stringToNumber<T>(
1368                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1369                    );
1370              } else {              } else {
1371                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1372              }              }
# Line 485  namespace Serialization { Line 1400  namespace Serialization {
1400          return _encodeBlob(s);          return _encodeBlob(s);
1401      }      }
1402    
1403        /*
1404         * Srx format history:
1405         * - 1.0: Initial version.
1406         * - 1.1: Adds "String" and "Array" data types.
1407         */
1408      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1409      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1410    
1411      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1412          String s;          String s;
# Line 612  namespace Serialization { Line 1532  namespace Serialization {
1532          return s;          return s;
1533      }      }
1534    
1535        static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1536            String s = _popStringBlob(p, end);
1537            rawData.resize(s.length() + 1);
1538            strcpy((char*)&rawData[0], &s[0]);
1539        }
1540    
1541      static time_t _popTimeBlob(const char*& p, const char* end) {      static time_t _popTimeBlob(const char*& p, const char* end) {
1542          const uint64_t i = _popIntBlob<uint64_t>(p, end);          const uint64_t i = _popIntBlob<uint64_t>(p, end);
1543          return (time_t) i;          return (time_t) i;
1544      }      }
1545    
1546      DataType _popDataTypeBlob(const char*& p, const char* end) {      static DataType _popDataTypeBlob(const char*& p, const char* end) {
1547          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1548          p   = blob.p;          p   = blob.p;
1549          end = blob.end;          end = blob.end;
# Line 668  namespace Serialization { Line 1594  namespace Serialization {
1594          if (p >= end) return m;          if (p >= end) return m;
1595    
1596          m.m_uid    = _popUIDBlob(p, end);          m.m_uid    = _popUIDBlob(p, end);
1597          m.m_offset = _popIntBlob<size_t>(p, end);          m.m_offset = _popIntBlob<ssize_t>(p, end);
1598          m.m_name   = _popStringBlob(p, end);          m.m_name   = _popStringBlob(p, end);
1599          m.m_type   = _popDataTypeBlob(p, end);          m.m_type   = _popDataTypeBlob(p, end);
1600          assert(m.type());          assert(m.type());
# Line 730  namespace Serialization { Line 1656  namespace Serialization {
1656                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1657              } else if (type.isBool()) {              } else if (type.isBool()) {
1658                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1659                } else if (type.isString()) {
1660                    _popStringBlob(p, end, obj.m_data);
1661              } else {              } else {
1662                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1663              }              }
# Line 801  namespace Serialization { Line 1729  namespace Serialization {
1729          m_timeModified = _popTimeBlob(p, end);          m_timeModified = _popTimeBlob(p, end);
1730      }      }
1731    
1732        /** @brief Fill this archive with the given serialized raw data.
1733         *
1734         * Calling this method will decode the given raw @a data and constructs a
1735         * (non-empty) Archive object according to that given serialized @a data
1736         * stream.
1737         *
1738         * After this method returned, you may then traverse the individual
1739         * objects by starting with accessing the rootObject() for example. Finally
1740         * you might call deserialize() to restore your native C++ objects with the
1741         * content of this archive.
1742         *
1743         * @param data - the previously serialized raw data stream to be decoded
1744         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1745         *         incompatible or corrupt data stream or format.
1746         */
1747      void Archive::decode(const RawData& data) {      void Archive::decode(const RawData& data) {
1748          m_rawData = data;          m_rawData = data;
1749          m_allObjects.clear();          m_allObjects.clear();
# Line 814  namespace Serialization { Line 1757  namespace Serialization {
1757          _popRootBlob(p, end);          _popRootBlob(p, end);
1758      }      }
1759    
1760        /** @brief Fill this archive with the given serialized raw C-buffer data.
1761         *
1762         * This method essentially works like the decode() method above, but just
1763         * uses another data type for the serialized raw data stream being passed to
1764         * this method.
1765         *
1766         * Calling this method will decode the given raw @a data and constructs a
1767         * (non-empty) Archive object according to that given serialized @a data
1768         * stream.
1769         *
1770         * After this method returned, you may then traverse the individual
1771         * objects by starting with accessing the rootObject() for example. Finally
1772         * you might call deserialize() to restore your native C++ objects with the
1773         * content of this archive.
1774         *
1775         * @param data - the previously serialized raw data stream to be decoded
1776         * @param size - size of @a data in bytes
1777         * @throws Exception if the provided raw @a data uses an invalid, unknown,
1778         *         incompatible or corrupt data stream or format.
1779         */
1780      void Archive::decode(const uint8_t* data, size_t size) {      void Archive::decode(const uint8_t* data, size_t size) {
1781          RawData rawData;          RawData rawData;
1782          rawData.resize(size);          rawData.resize(size);
# Line 821  namespace Serialization { Line 1784  namespace Serialization {
1784          decode(rawData);          decode(rawData);
1785      }      }
1786    
1787        /** @brief Raw data stream of this archive content.
1788         *
1789         * Call this method to get a raw data stream for the current content of this
1790         * archive, which you may use to i.e. store on disk or send vie network to
1791         * another machine for deserializing there. This method only returns a
1792         * meaningful content if this is a non-empty archive, that is if you either
1793         * serialized with this Archive object or decoded a raw data stream to this
1794         * Archive object before. If this is an empty archive instead, then this
1795         * method simply returns an empty raw data stream (of size 0) instead.
1796         *
1797         * Note that whenever you call this method, the "modified" state of this
1798         * archive will be reset to @c false.
1799         *
1800         * @see isModified()
1801         */
1802      const RawData& Archive::rawData() {      const RawData& Archive::rawData() {
1803          if (m_isModified) encode();          if (m_isModified) encode();
1804          return m_rawData;          return m_rawData;
1805      }      }
1806    
1807        /** @brief Name of the encoding format used by this Archive class.
1808         *
1809         * This method returns the name of the encoding format used to encode
1810         * serialized raw data streams.
1811         */
1812      String Archive::rawDataFormat() const {      String Archive::rawDataFormat() const {
1813          return MAGIC_START;          return MAGIC_START;
1814      }      }
1815    
1816        /** @brief Whether this archive was modified.
1817         *
1818         * This method returns the current "modified" state of this archive. When
1819         * either decoding a previously serialized raw data stream or after
1820         * serializing native C++ objects to this archive the modified state will
1821         * initially be set to @c false. However whenever you are modifying the
1822         * abstract data model of this archive afterwards, for example by removing
1823         * objects from this archive by calling remove() or removeMember(), or by
1824         * altering object values for example by calling setIntValue(), then the
1825         * "modified" state of this archive will automatically be set to @c true.
1826         *
1827         * You can reset the "modified" state explicitly at any time, by calling
1828         * rawData().
1829         */
1830      bool Archive::isModified() const {      bool Archive::isModified() const {
1831          return m_isModified;          return m_isModified;
1832      }      }
1833    
1834        /** @brief Clear content of this archive.
1835         *
1836         * Drops the entire content of this archive and thus resets this archive
1837         * back to become an empty archive.
1838         */
1839      void Archive::clear() {      void Archive::clear() {
1840          m_allObjects.clear();          m_allObjects.clear();
1841          m_operation = OPERATION_NONE;          m_operation = OPERATION_NONE;
# Line 843  namespace Serialization { Line 1845  namespace Serialization {
1845          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1846      }      }
1847    
1848        /** @brief Optional name of this archive.
1849         *
1850         * Returns the optional name of this archive that you might have assigned
1851         * to this archive before by calling setName(). If you haven't assigned any
1852         * name to this archive before, then this method simply returns an empty
1853         * string instead.
1854         */
1855      String Archive::name() const {      String Archive::name() const {
1856          return m_name;          return m_name;
1857      }      }
1858    
1859        /** @brief Assign a name to this archive.
1860         *
1861         * You may optionally assign an arbitrary name to this archive. The name
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 name - arbitrary new name for this archive
1867         */
1868      void Archive::setName(String name) {      void Archive::setName(String name) {
1869          if (m_name == name) return;          if (m_name == name) return;
1870          m_name = name;          m_name = name;
1871          m_isModified = true;          m_isModified = true;
1872      }      }
1873    
1874        /** @brief Optional comments for this archive.
1875         *
1876         * Returns the optional comments for this archive that you might have
1877         * assigned to this archive before by calling setComment(). If you haven't
1878         * assigned any comment to this archive before, then this method simply
1879         * returns an empty string instead.
1880         */
1881      String Archive::comment() const {      String Archive::comment() const {
1882          return m_comment;          return m_comment;
1883      }      }
1884    
1885        /** @brief Assign a comment to this archive.
1886         *
1887         * You may optionally assign arbitrary comments to this archive. The comment
1888         * will be stored along with the archive, that is it will encoded with the
1889         * resulting raw data stream, and accordingly it will be decoded from the
1890         * raw data stream later on.
1891         *
1892         * @param comment - arbitrary new comment for this archive
1893         */
1894      void Archive::setComment(String comment) {      void Archive::setComment(String comment) {
1895          if (m_comment == comment) return;          if (m_comment == comment) return;
1896          m_comment = comment;          m_comment = comment;
# Line 880  namespace Serialization { Line 1914  namespace Serialization {
1914          return *pTm;          return *pTm;
1915      }      }
1916    
1917        /** @brief Date and time when this archive was initially created.
1918         *
1919         * Returns a UTC time stamp (date and time) when this archive was initially
1920         * created.
1921         */
1922      time_t Archive::timeStampCreated() const {      time_t Archive::timeStampCreated() const {
1923          return m_timeCreated;          return m_timeCreated;
1924      }      }
1925    
1926        /** @brief Date and time when this archive was modified for the last time.
1927         *
1928         * Returns a UTC time stamp (date and time) when this archive was modified
1929         * for the last time.
1930         */
1931      time_t Archive::timeStampModified() const {      time_t Archive::timeStampModified() const {
1932          return m_timeModified;          return m_timeModified;
1933      }      }
1934    
1935        /** @brief Date and time when this archive was initially created.
1936         *
1937         * Returns a calendar time information representing the date and time when
1938         * this archive was initially created. The optional @a base parameter may
1939         * be used to define to which time zone the returned data and time shall be
1940         * related to.
1941         *
1942         * @param base - (optional) time zone the result shall relate to, by default
1943         *               UTC time (Greenwhich Mean Time) is assumed instead
1944         */
1945      tm Archive::dateTimeCreated(time_base_t base) const {      tm Archive::dateTimeCreated(time_base_t base) const {
1946          return _convertTimeStamp(m_timeCreated, base);          return _convertTimeStamp(m_timeCreated, base);
1947      }      }
1948    
1949        /** @brief Date and time when this archive was modified for the last time.
1950         *
1951         * Returns a calendar time information representing the date and time when
1952         * this archive has been modified for the last time. The optional @a base
1953         * parameter may be used to define to which time zone the returned date and
1954         * time shall be related to.
1955         *
1956         * @param base - (optional) time zone the result shall relate to, by default
1957         *               UTC time (Greenwhich Mean Time) is assumed instead
1958         */
1959      tm Archive::dateTimeModified(time_base_t base) const {      tm Archive::dateTimeModified(time_base_t base) const {
1960          return _convertTimeStamp(m_timeModified, base);          return _convertTimeStamp(m_timeModified, base);
1961      }      }
1962    
1963        /** @brief Remove a member variable from the given object.
1964         *
1965         * Removes the member variable @a member from its containing object
1966         * @a parent and sets the modified state of this archive to @c true.
1967         * If the given @a parent object does not contain the given @a member then
1968         * this method does nothing.
1969         *
1970         * This method provides a means of "partial" deserialization. By removing
1971         * either objects or members from this archive before calling deserialize(),
1972         * only the remaining objects and remaining members will be restored by this
1973         * framework, all other data of your C++ classes remain untouched.
1974         *
1975         * @param parent - Object which contains @a member
1976         * @param member - member to be removed
1977         * @see isModified() for details about the modified state.
1978         * @see Object for more details about the overall object reflection concept.
1979         */
1980      void Archive::removeMember(Object& parent, const Member& member) {      void Archive::removeMember(Object& parent, const Member& member) {
1981          parent.remove(member);          parent.remove(member);
1982          m_isModified = true;          m_isModified = true;
1983      }      }
1984    
1985        /** @brief Remove an object from this archive.
1986         *
1987         * Removes the object @obj from this archive and sets the modified state of
1988         * this archive to @c true. If the passed object is either invalid, or does
1989         * not exist in this archive, then this method does nothing.
1990         *
1991         * This method provides a means of "partial" deserialization. By removing
1992         * either objects or members from this archive before calling deserialize(),
1993         * only the remaining objects and remaining members will be restored by this
1994         * framework, all other data of your C++ classes remain untouched.
1995         *
1996         * @param obj - the object to be removed from this archive
1997         * @see isModified() for details about the modified state.
1998         * @see Object for more details about the overall object reflection concept.
1999         */
2000      void Archive::remove(const Object& obj) {      void Archive::remove(const Object& obj) {
2001          //FIXME: Should traverse from root object and remove all members associated with this object          //FIXME: Should traverse from root object and remove all members associated with this object
2002          if (!obj.uid()) return;          if (!obj.uid()) return;
# Line 908  namespace Serialization { Line 2004  namespace Serialization {
2004          m_isModified = true;          m_isModified = true;
2005      }      }
2006    
2007        /** @brief Access object by its unique identifier.
2008         *
2009         * Returns the object of this archive with the given unique identifier
2010         * @a uid. If the given @a uid is invalid, or if this archive does not
2011         * contain an object with the given unique identifier, then this method
2012         * returns an invalid object instead.
2013         *
2014         * @param uid - unique identifier of sought object
2015         * @see Object for more details about the overall object reflection concept.
2016         * @see Object::isValid() for valid/invalid objects
2017         */
2018      Object& Archive::objectByUID(const UID& uid) {      Object& Archive::objectByUID(const UID& uid) {
2019          return m_allObjects[uid];          return m_allObjects[uid];
2020      }      }
2021    
2022        /** @brief Set the current version for the given object.
2023         *
2024         * Essentially behaves like above's setVersion() method, it just uses the
2025         * abstract reflection data type instead for the respective @a object being
2026         * passed to this method. Refer to above's setVersion() documentation about
2027         * the precise behavior details of setVersion().
2028         *
2029         * @param object - object to set the current version for
2030         * @param v - new current version to set for @a object
2031         */
2032        void Archive::setVersion(Object& object, Version v) {
2033            if (!object) return;
2034            object.setVersion(v);
2035            m_isModified = true;
2036        }
2037    
2038        /** @brief Set the minimum version for the given object.
2039         *
2040         * Essentially behaves like above's setMinVersion() method, it just uses the
2041         * abstract reflection data type instead for the respective @a object being
2042         * passed to this method. Refer to above's setMinVersion() documentation
2043         * about the precise behavior details of setMinVersion().
2044         *
2045         * @param object - object to set the minimum version for
2046         * @param v - new minimum version to set for @a object
2047         */
2048        void Archive::setMinVersion(Object& object, Version v) {
2049            if (!object) return;
2050            object.setMinVersion(v);
2051            m_isModified = true;
2052        }
2053    
2054        /** @brief Set new value for given @c enum object.
2055         *
2056         * Sets the new @a value to the given @c enum @a object.
2057         *
2058         * @param object - the @c enum object to be changed
2059         * @param value - the new value to be assigned to the @a object
2060         * @throws Exception if @a object is not an @c enum type.
2061         */
2062      void Archive::setEnumValue(Object& object, uint64_t value) {      void Archive::setEnumValue(Object& object, uint64_t value) {
2063          if (!object) return;          if (!object) return;
2064          if (!object.type().isEnum())          if (!object.type().isEnum())
# Line 944  namespace Serialization { Line 2091  namespace Serialization {
2091          m_isModified = true;          m_isModified = true;
2092      }      }
2093    
2094        /** @brief Set new integer value for given integer object.
2095         *
2096         * Sets the new integer @a value to the given integer @a object. Currently
2097         * this framework handles any integer data type up to 64 bit. For larger
2098         * integer types an assertion failure will be raised.
2099         *
2100         * @param object - the integer object to be changed
2101         * @param value - the new value to be assigned to the @a object
2102         * @throws Exception if @a object is not an integer type.
2103         */
2104      void Archive::setIntValue(Object& object, int64_t value) {      void Archive::setIntValue(Object& object, int64_t value) {
2105          if (!object) return;          if (!object) return;
2106          if (!object.type().isInteger())          if (!object.type().isInteger())
# Line 983  namespace Serialization { Line 2140  namespace Serialization {
2140          m_isModified = true;          m_isModified = true;
2141      }      }
2142    
2143        /** @brief Set new floating point value for given floating point object.
2144         *
2145         * Sets the new floating point @a value to the given floating point
2146         * @a object. Currently this framework supports single precision @c float
2147         * and double precision @c double floating point data types. For all other
2148         * floating point types this method will raise an assertion failure.
2149         *
2150         * @param object - the floating point object to be changed
2151         * @param value - the new value to be assigned to the @a object
2152         * @throws Exception if @a object is not a floating point based type.
2153         */
2154      void Archive::setRealValue(Object& object, double value) {      void Archive::setRealValue(Object& object, double value) {
2155          if (!object) return;          if (!object) return;
2156          if (!object.type().isReal())          if (!object.type().isReal())
# Line 1005  namespace Serialization { Line 2173  namespace Serialization {
2173          m_isModified = true;          m_isModified = true;
2174      }      }
2175    
2176        /** @brief Set new boolean value for given boolean object.
2177         *
2178         * Sets the new boolean @a value to the given boolean @a object.
2179         *
2180         * @param object - the boolean object to be changed
2181         * @param value - the new value to be assigned to the @a object
2182         * @throws Exception if @a object is not a boolean type.
2183         */
2184      void Archive::setBoolValue(Object& object, bool value) {      void Archive::setBoolValue(Object& object, bool value) {
2185          if (!object) return;          if (!object) return;
2186          if (!object.type().isBool())          if (!object.type().isBool())
# Line 1022  namespace Serialization { Line 2198  namespace Serialization {
2198          m_isModified = true;          m_isModified = true;
2199      }      }
2200    
2201        /** @brief Set new textual string for given String object.
2202         *
2203         * Sets the new textual string @a value to the given String @a object.
2204         *
2205         * @param object - the String object to be changed
2206         * @param value - the new textual string to be assigned to the @a object
2207         * @throws Exception if @a object is not a String type.
2208         */
2209        void Archive::setStringValue(Object& object, String value) {
2210            if (!object) return;
2211            if (!object.type().isString())
2212                throw Exception("Not a String data type");
2213            Object* pObject = &object;
2214            if (object.type().isPointer()) {
2215                Object& obj = objectByUID(object.uid(1));
2216                if (!obj) return;
2217                pObject = &obj;
2218            }
2219            pObject->m_data.resize(value.length() + 1);
2220            char* ptr = (char*) &pObject->m_data[0];
2221            strcpy(ptr, &value[0]);
2222            m_isModified = true;
2223        }
2224    
2225        /** @brief Automatically cast and assign appropriate value to object.
2226         *
2227         * This method automatically converts the given @a value from textual string
2228         * representation into the appropriate data format of the requested
2229         * @a object. So this method is a convenient way to change values of objects
2230         * in this archive with your applications in automated way, i.e. for
2231         * implementing an editor where the user is able to edit values of objects
2232         * in this archive by entering the values as text with a keyboard.
2233         *
2234         * @throws Exception if the passed @a object is not a fundamental, primitive
2235         *         data type or if the provided textual value cannot be converted
2236         *         into an appropriate value for the requested object.
2237         */
2238      void Archive::setAutoValue(Object& object, String value) {      void Archive::setAutoValue(Object& object, String value) {
2239          if (!object) return;          if (!object) return;
2240          const DataType& type = object.type();          const DataType& type = object.type();
# Line 1029  namespace Serialization { Line 2242  namespace Serialization {
2242              setIntValue(object, atoll(value.c_str()));              setIntValue(object, atoll(value.c_str()));
2243          else if (type.isReal())          else if (type.isReal())
2244              setRealValue(object, atof(value.c_str()));              setRealValue(object, atof(value.c_str()));
2245          else if (type.isBool())          else if (type.isBool()) {
2246              setBoolValue(object, atof(value.c_str()));              String val = toLowerCase(value);
2247                if (val == "true" || val == "yes" || val == "1")
2248                    setBoolValue(object, true);
2249                else if (val == "false" || val == "no" || val == "0")
2250                    setBoolValue(object, false);
2251                else
2252                    setBoolValue(object, atof(value.c_str()));
2253            } else if (type.isString())
2254                setStringValue(object, value);
2255          else if (type.isEnum())          else if (type.isEnum())
2256              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2257          else          else
2258              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
2259      }      }
2260    
2261        /** @brief Get value of object as string.
2262         *
2263         * Converts the current value of the given @a object into a textual string
2264         * and returns that string.
2265         *
2266         * @param object - object whose value shall be retrieved
2267         * @throws Exception if the given object is either invalid, or if the object
2268         *         is not a fundamental, primitive data type.
2269         */
2270      String Archive::valueAsString(const Object& object) {      String Archive::valueAsString(const Object& object) {
2271          if (!object)          if (!object)
2272              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 1051  namespace Serialization { Line 2281  namespace Serialization {
2281          return _primitiveObjectValueToString(*pObject);          return _primitiveObjectValueToString(*pObject);
2282      }      }
2283    
2284        /** @brief Get integer value of object.
2285         *
2286         * Returns the current integer value of the requested integer @a object or
2287         * @c enum object.
2288         *
2289         * @param object - object whose value shall be retrieved
2290         * @throws Exception if the given object is either invalid, or if the object
2291         *         is neither an integer nor @c enum data type.
2292         */
2293      int64_t Archive::valueAsInt(const Object& object) {      int64_t Archive::valueAsInt(const Object& object) {
2294          if (!object)          if (!object)
2295              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 1065  namespace Serialization { Line 2304  namespace Serialization {
2304          return _primitiveObjectValueToNumber<int64_t>(*pObject);          return _primitiveObjectValueToNumber<int64_t>(*pObject);
2305      }      }
2306    
2307        /** @brief Get floating point value of object.
2308         *
2309         * Returns the current floating point value of the requested floating point
2310         * @a object.
2311         *
2312         * @param object - object whose value shall be retrieved
2313         * @throws Exception if the given object is either invalid, or if the object
2314         *         is not a floating point based type.
2315         */
2316      double Archive::valueAsReal(const Object& object) {      double Archive::valueAsReal(const Object& object) {
2317          if (!object)          if (!object)
2318              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 1079  namespace Serialization { Line 2327  namespace Serialization {
2327          return _primitiveObjectValueToNumber<double>(*pObject);          return _primitiveObjectValueToNumber<double>(*pObject);
2328      }      }
2329    
2330        /** @brief Get boolean value of object.
2331         *
2332         * Returns the current boolean value of the requested boolean @a object.
2333         *
2334         * @param object - object whose value shall be retrieved
2335         * @throws Exception if the given object is either invalid, or if the object
2336         *         is not a boolean data type.
2337         */
2338      bool Archive::valueAsBool(const Object& object) {      bool Archive::valueAsBool(const Object& object) {
2339          if (!object)          if (!object)
2340              throw Exception("Invalid object");              throw Exception("Invalid object");
# Line 1093  namespace Serialization { Line 2349  namespace Serialization {
2349          return _primitiveObjectValueToNumber<bool>(*pObject);          return _primitiveObjectValueToNumber<bool>(*pObject);
2350      }      }
2351    
2352        Archive::operation_t Archive::operation() const {
2353            return m_operation;
2354        }
2355    
2356      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2357      // *      // *
2358    
# Line 1114  namespace Serialization { Line 2374  namespace Serialization {
2374          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2375      }      }
2376    
2377        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2378            assert(dstObj.type().isString());
2379            assert(dstObj.type() == srcObj.type());
2380            String* pDst = (String*)(void*)dstObj.uid().id;
2381            *pDst = (String) (const char*) &srcObj.rawData()[0];
2382        }
2383    
2384        void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2385            assert(dstObj.type().isArray());
2386            assert(dstObj.type() == srcObj.type());
2387            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2388        }
2389    
2390      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2391          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2392          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 1140  namespace Serialization { Line 2413  namespace Serialization {
2413          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2414    
2415          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2416              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2417                    syncString(dstObj, srcObj);
2418                else
2419                    syncPrimitive(dstObj, srcObj);
2420              return; // end of recursion              return; // end of recursion
2421          }          }
2422    
2423            if (dstObj.type().isArray()) {
2424                syncArray(dstObj, srcObj);
2425                return;
2426            }
2427    
2428          if (dstObj.type().isPointer()) {          if (dstObj.type().isPointer()) {
2429              syncPointer(dstObj, srcObj);              syncPointer(dstObj, srcObj);
2430              return;              return;
# Line 1192  namespace Serialization { Line 2473  namespace Serialization {
2473      // *************** Exception ***************      // *************** Exception ***************
2474      // *      // *
2475    
2476        Exception::Exception() {
2477        }
2478    
2479        Exception::Exception(String format, ...) {
2480            va_list arg;
2481            va_start(arg, format);
2482            Message = assemble(format, arg);
2483            va_end(arg);
2484        }
2485    
2486        Exception::Exception(String format, va_list arg) {
2487            Message = assemble(format, arg);
2488        }
2489    
2490        /** @brief Print exception message to stdout.
2491         *
2492         * Prints the message of this Exception to the currently defined standard
2493         * output (that is to the terminal console for example).
2494         */
2495      void Exception::PrintMessage() {      void Exception::PrintMessage() {
2496          std::cout << "Serialization::Exception: " << Message << std::endl;          std::cout << "Serialization::Exception: " << Message << std::endl;
2497      }      }
2498    
2499        String Exception::assemble(String format, va_list arg) {
2500            char* buf = NULL;
2501            vasprintf(&buf, format.c_str(), arg);
2502            String s = buf;
2503            free(buf);
2504            return s;
2505        }
2506    
2507  } // namespace Serialization  } // namespace Serialization

Legend:
Removed from v.3173  
changed lines
  Added in v.3775

  ViewVC Help
Powered by ViewVC