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

Legend:
Removed from v.3168  
changed lines
  Added in v.3464

  ViewVC Help
Powered by ViewVC