/[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 3333 by schoenebeck, Sat Jul 29 09:57:08 2017 UTC revision 3777 by schoenebeck, Sat May 23 19:55:32 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 63  namespace Serialization { Line 70  namespace Serialization {
70      // *************** DataType ***************      // *************** DataType ***************
71      // *      // *
72    
73      /** @brief Default constructor.      /** @brief Default constructor (as "invalid" DataType).
74       *       *
75       * Initializes a DataType object as being an "invalid" DataType object.       * Initializes a DataType object as being an "invalid" DataType object.
76       * Thus calling isValid(), after creating a DataType object with this       * Thus calling isValid(), after creating a DataType object with this
# Line 77  namespace Serialization { Line 84  namespace Serialization {
84          m_isPointer = false;          m_isPointer = false;
85      }      }
86    
87      DataType::DataType(bool isPointer, int size, String baseType, String customType) {      /** @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", "Set", "enum", "union" or "class"
105         * @param customType1 - this is only used for base types "enum", "union",
106         *                     "class", "Array", "Set" or "Map", in which case this
107         *                      identifies the 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         * @param customType2 - this is only used for @c Map<> objects in which case
111         *                      it identifies the map's value type (i.e. 2nd
112         *                      template parameter of map)
113         */
114        DataType::DataType(bool isPointer, int size, String baseType,
115                           String customType1, String customType2)
116        {
117          m_size = size;          m_size = size;
118          m_isPointer = isPointer;          m_isPointer = isPointer;
119          m_baseTypeName = baseType;          m_baseTypeName = baseType;
120          m_customTypeName = customType;          m_customTypeName = customType1;
121            m_customTypeName2 = customType2;
122      }      }
123    
124      /** @brief Check if this is a valid DataType object.      /** @brief Check if this is a valid DataType object.
# Line 113  namespace Serialization { Line 150  namespace Serialization {
150       * (this DataType instance is reflecting) is a C/C++ @c struct or @c class       * (this DataType instance is reflecting) is a C/C++ @c struct or @c class
151       * type.       * type.
152       *       *
153         * @note: Data types which enjoy out of the box serialization support by
154         * this framework, like @c String and @c Array<> are @b NOT handled as class
155         * data types by this framwork. So @c isClass() returns @c false for e.g.
156         * @c String and any @c Array<> based data type.
157         *
158       * Note that in the following example:       * Note that in the following example:
159       * @code       * @code
160       * struct Foo {       * struct Foo {
# Line 137  namespace Serialization { Line 179  namespace Serialization {
179       * (this DataType instance is reflecting) is a primitive, fundamental C/C++       * (this DataType instance is reflecting) is a primitive, fundamental C/C++
180       * data type. Those are fundamental data types which are already predefined       * data type. Those are fundamental data types which are already predefined
181       * by the C/C++ language, for example: @c char, @c int, @c float, @c double,       * by the C/C++ language, for example: @c char, @c int, @c float, @c double,
182       * @c bool, but also @b any pointer types like @c int*, @c double**, but       * @c bool, but also @c String objects and @b any pointer types like
183       * including pointers to user defined types like:       * @c int*, @c double**, but including pointers to user defined types like:
184       * @code       * @code
185       * struct Foo {       * struct Foo {
186       *     int  a;       *     int  a;
# Line 152  namespace Serialization { Line 194  namespace Serialization {
194       * @see isPointer()       * @see isPointer()
195       */       */
196      bool DataType::isPrimitive() const {      bool DataType::isPrimitive() const {
197          return !isClass();          return !isClass() && !isArray() && !isSet() && !isMap();
198        }
199    
200        /** @brief Whether this is a C++ @c String data type.
201         *
202         * Returns @c true if the respective native C/C++ object, member or variable
203         * (this DataType instance is reflecting) is a C++ @c String object (a.k.a.
204         * @c std::string from the C++ STL).
205         *
206         * Note that this framework handles @c String objects as if they were a
207         * fundamental, primitive C/C++ data type, so @c isPrimitive() returns
208         * @c true for strings.
209         */
210        bool DataType::isString() const {
211            return m_baseTypeName == "String";
212      }      }
213    
214      /** @brief Whether this is an integer C/C++ data type.      /** @brief Whether this is an integer C/C++ data type.
# Line 220  namespace Serialization { Line 276  namespace Serialization {
276          return m_baseTypeName == "enum";          return m_baseTypeName == "enum";
277      }      }
278    
279        /** @brief Whether this is a C++ @c Array<> object type.
280         *
281         * Returns @c true if the respective native C/C++ object, member or variable
282         * (this DataType instance is reflecting) is a C++ @c Array<> container
283         * object type.
284         *
285         * @note: This framework handles @c Array<> types neither as primitive
286         * types, nor as class types. So @c isPrimitive() and @c isClass() both
287         * return @c false for arrays.
288         *
289         * @see isPointer()
290         */
291        bool DataType::isArray() const {
292            return m_baseTypeName == "Array";
293        }
294    
295        /** @brief Whether this is a C++ @c Set<> object type.
296         *
297         * Returns @c true if the respective native C/C++ object, member or variable
298         * (this DataType instance is reflecting) is a C++ @c Set<> unique container
299         * object type.
300         *
301         * @note: This framework handles @c Set<> types neither as primitive
302         * types, nor as class types. So @c isPrimitive() and @c isClass() both
303         * return @c false for sets.
304         *
305         * @see isPointer()
306         */
307        bool DataType::isSet() const {
308            return m_baseTypeName == "Set";
309        }
310    
311        /** @brief Whether this is a C++ @c Map<> object type.
312         *
313         * Returns @c true if the respective native C/C++ object, member or variable
314         * (this DataType instance is reflecting) is an associative sorted C++
315         * @c Map<> container object type.
316         *
317         * @note: This framework handles @c Map<> types neither as primitive
318         * types, nor as class types. So @c isPrimitive() and @c isClass() both
319         * return @c false for maps.
320         *
321         * @see isPointer()
322         */
323        bool DataType::isMap() const {
324            return m_baseTypeName == "Map";
325        }
326    
327      /** @brief Whether this is a signed integer C/C++ data type.      /** @brief Whether this is a signed integer C/C++ data type.
328       *       *
329       * Returns @c true if the respective native C/C++ object, member or variable       * Returns @c true if the respective native C/C++ object, member or variable
# Line 259  namespace Serialization { Line 363  namespace Serialization {
363      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
364          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
365                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
366                   m_customTypeName2 == other.m_customTypeName2 &&
367                 (m_size == other.m_size || (isClass() && other.isClass())) &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
368                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
369      }      }
# Line 286  namespace Serialization { Line 391  namespace Serialization {
391      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
392          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
393                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
394                 m_customTypeName  < other.m_customTypeName ||                (m_customTypeName  < other.m_customTypeName ||
395                (m_customTypeName == other.m_customTypeName &&                (m_customTypeName == other.m_customTypeName &&
396                 m_size  < other.m_size ||                (m_customTypeName2  < other.m_customTypeName2 ||
397                  (m_customTypeName2 == other.m_customTypeName2 &&
398                  (m_size  < other.m_size ||
399                (m_size == other.m_size &&                (m_size == other.m_size &&
400                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)))))));
401      }      }
402    
403      /** @brief Greater than comparison.      /** @brief Greater than comparison.
# Line 326  namespace Serialization { Line 433  namespace Serialization {
433          String s = m_baseTypeName;          String s = m_baseTypeName;
434          if (!m_customTypeName.empty())          if (!m_customTypeName.empty())
435              s += " " + customTypeName(true);              s += " " + customTypeName(true);
436            if (!m_customTypeName2.empty())
437                s += " " + customTypeName2(true);
438          if (isPointer())          if (isPointer())
439              s += " pointer";              s += " pointer";
440          return s;          return s;
# Line 358  namespace Serialization { Line 467  namespace Serialization {
467       * @endcode       * @endcode
468       * this method would return for both @c i and @c pi the string @c "uint64" !       * this method would return for both @c i and @c pi the string @c "uint64" !
469       *       *
470       * @see isPointer(), customTypeName()       * @see isPointer(), customTypeName(), customTypeName2()
471       */       */
472      String DataType::baseTypeName() const {      String DataType::baseTypeName() const {
473          return m_baseTypeName;          return m_baseTypeName;
474      }      }
475    
476      /** @brief The user defined C/C++ data type name of this data type.      static String _demangleTypeName(const char* name) {
477       *  #ifdef _MSC_VER
478       * Call this method on user defined C/C++ data types like @c enum, @c struct          const size_t MAXLENGTH = 1024;
479       * and @c class types to retrieve the user defined type name portion of          char result[MAXLENGTH];
480       * those data types. Note that this method is only intended for such user  
481       * defined data types. For all fundamental, primitive data types (like i.e.          //FIXME: calling UnDecorateSymbolName() is not thread safe!
482       * @c int) this method returns an empty string instead.          //Skip the first char
483            size_t size = UnDecorateSymbolName(name + 1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
484            if (size)
485            {
486                return result;
487            }
488            return name;
489    #else
490            int status;
491            char* result =
492                abi::__cxa_demangle(name, 0, 0, &status);
493            String sResult = result;
494            free(result);
495            return (status == 0) ? sResult : name;
496    #endif
497        }
498    
499        /** @brief The 1st user defined C/C++ data type name of this data type.
500         *
501         * Call this method on user defined C/C++ data types like @c enum,
502         * @c struct, @c class or @c Array<> types to retrieve the user defined type
503         * name portion of those data types. Note that this method is only intended
504         * for such user defined data types. For all fundamental, primitive data
505         * types (like i.e. @c int) this method returns an empty string instead.
506       *       *
507       * This method takes an optional boolean argument @b demangle, which allows       * This method takes an optional boolean argument @b demangle, which allows
508       * you define whether you are interested in the raw C++ type name or rather       * you define whether you are interested in the raw C++ type name or rather
# Line 395  namespace Serialization { Line 527  namespace Serialization {
527       * In the latter example @c customTypeName(true) would return for both       * In the latter example @c customTypeName(true) would return for both
528       * @c foo and @c pFoo the string @c "Foo" as return value of this method.       * @c foo and @c pFoo the string @c "Foo" as return value of this method.
529       *       *
530       * @see isPointer(), baseTypeName()       * @b Windows: please note that the current implementation of this method
531         * on Windows is @b not thread safe!
532         *
533         * @see baseTypeName(), customTypeName2(), isPointer()
534       */       */
535      String DataType::customTypeName(bool demangle) const {      String DataType::customTypeName(bool demangle) const {
536          if (!demangle) return m_customTypeName;          if (!demangle) return m_customTypeName;
537          int status;          return _demangleTypeName(m_customTypeName.c_str());
538          const char* result =      }
539              abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);  
540          return (status == 0) ? result : m_customTypeName;      /** @brief The 2nd user defined C/C++ data type name of this data type.
541         *
542         * This is currently only used for @c Map<> data types in which case this
543         * method returns the map's value type (i.e. map's 2nd template parameter).
544         *
545         * @see baseTypeName(), customTypeName()
546         */
547        String DataType::customTypeName2(bool demangle) const {
548            if (!demangle) return m_customTypeName2;
549            return _demangleTypeName(m_customTypeName2.c_str());
550      }      }
551    
552      // *************** Member ***************      // *************** Member ***************
# Line 425  namespace Serialization { Line 569  namespace Serialization {
569          m_offset = 0;          m_offset = 0;
570      }      }
571    
572      Member::Member(String name, UID uid, size_t offset, DataType type) {      Member::Member(String name, UID uid, ssize_t offset, DataType type) {
573          m_name = name;          m_name = name;
574          m_uid  = uid;          m_uid  = uid;
575          m_offset = offset;          m_offset = offset;
# Line 507  namespace Serialization { Line 651  namespace Serialization {
651       * @c b and @c c instead. For most 64 bit architectures this example would       * @c b and @c c instead. For most 64 bit architectures this example would
652       * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16       * now still return @c 0 for member @c a, but @c 8 for member @c b and @c 16
653       * for member @c c.       * for member @c c.
654         *
655         * @note Offset is intended for native members only, that is member
656         * variables which are memory located directly within the associated parent
657         * data structure. For members allocated on the heap @c offset() always
658         * returns @c -1 instead since there is no constant, static offset
659         * relationship between data on the heap and the parent structure owning
660         * their life-time control.
661       */       */
662      size_t Member::offset() const {      ssize_t Member::offset() const {
663          return m_offset;          return m_offset;
664      }      }
665    
# Line 573  namespace Serialization { Line 724  namespace Serialization {
724      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
725          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
726                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
727                 m_offset  < other.m_offset ||                (m_offset  < other.m_offset ||
728                (m_offset == other.m_offset &&                (m_offset == other.m_offset &&
729                 m_name  < other.m_name ||                (m_name  < other.m_name ||
730                (m_name == other.m_name &&                (m_name == other.m_name &&
731                 m_type < other.m_type)));                 m_type < other.m_type)))));
732      }      }
733    
734      /** @brief Greater than comparison.      /** @brief Greater than comparison.
# Line 669  namespace Serialization { Line 820  namespace Serialization {
820          return (index < m_uid.size()) ? m_uid[index] : NO_UID;          return (index < m_uid.size()) ? m_uid[index] : NO_UID;
821      }      }
822    
823        static void _setNativeValueFromString(void* ptr, const DataType& type, const char* s) {
824            if (type.isPrimitive() && !type.isPointer()) {
825                if (type.isInteger() || type.isEnum()) {
826                    if (type.isSigned()) {
827                        if (type.size() == 1)
828                            *(int8_t*)ptr = (int8_t) atoll(s);
829                        else if (type.size() == 2)
830                            *(int16_t*)ptr = (int16_t) atoll(s);
831                        else if (type.size() == 4)
832                            *(int32_t*)ptr = (int32_t) atoll(s);
833                        else if (type.size() == 8)
834                            *(int64_t*)ptr = (int64_t) atoll(s);
835                        else
836                            assert(false /* unknown signed int type size */);
837                    } else {
838                        if (type.size() == 1)
839                            *(uint8_t*)ptr = (uint8_t) atoll(s);
840                        else if (type.size() == 2)
841                            *(uint16_t*)ptr = (uint16_t) atoll(s);
842                        else if (type.size() == 4)
843                            *(uint32_t*)ptr = (uint32_t) atoll(s);
844                        else if (type.size() == 8)
845                            *(uint64_t*)ptr = (uint64_t) atoll(s);
846                        else
847                            assert(false /* unknown unsigned int type size */);
848                    }
849                } else if (type.isReal()) {
850                    if (type.size() == sizeof(float))
851                        *(float*)ptr = (float) atof(s);
852                    else if (type.size() == sizeof(double))
853                        *(double*)ptr = (double) atof(s);
854                    else
855                        assert(false /* unknown floating point type */);
856                } else if (type.isBool()) {
857                    String lower = toLowerCase(s);
858                    const bool b = lower != "0" && lower != "false" && lower != "no";
859                    *(bool*)ptr = b;
860                } else if (type.isString()) {
861                    *(String*)ptr = s;
862                } else {
863                    assert(false /* no built-in cast from string support for this data type */);
864                }
865            }
866        }
867    
868        /** @brief Cast from string to object's data type and assign value natively.
869         *
870         * The passed String @a s is decoded from its string representation to this
871         * object's corresponding native data type, then that casted value is
872         * assigned to the native memory location this Object is referring to.
873         *
874         * Note: This method may only be called for data types which enjoy built-in
875         * support for casting from string to their native data type, which are
876         * basically primitive data types (e.g. @c int, @c bool, @c double, etc.) or
877         * @c String objects. For all other data types calling this method will
878         * cause an assertion fault at runtime.
879         *
880         * @param s - textual string representation of the value to be assigned to
881         *            this object
882         */
883        void Object::setNativeValueFromString(const String& s) {
884            const ID& id = uid().id;
885            void* ptr = (void*)id;
886            _setNativeValueFromString(ptr, m_type, s.c_str());
887        }
888    
889      /** @brief Unique identifier chain of this Object.      /** @brief Unique identifier chain of this Object.
890       *       *
891       * Returns the entire unique identifier chain of this Object.       * Returns the entire unique identifier chain of this Object.
# Line 719  namespace Serialization { Line 936  namespace Serialization {
936       * In case this Object is reflecting a native C/C++ @c struct or @c class       * In case this Object is reflecting a native C/C++ @c struct or @c class
937       * type, then this method returns the version of that native C/C++ @c struct       * type, then this method returns the version of that native C/C++ @c struct
938       * or @c class layout or implementation. For primitive, fundamental C/C++       * or @c class layout or implementation. For primitive, fundamental C/C++
939       * data types the return value of this method has no meaning.       * data types (including @c String objects) the return value of this method
940         * has no meaning.
941       *       *
942       * @see Archive::setVersion() for more details about this overall topic.       * @see Archive::setVersion() for more details about this overall topic.
943       */       */
# Line 732  namespace Serialization { Line 950  namespace Serialization {
950       * In case this Object is reflecting a native C/C++ @c struct or @c class       * In case this Object is reflecting a native C/C++ @c struct or @c class
951       * type, then this method returns the "minimum" version of that native C/C++       * type, then this method returns the "minimum" version of that native C/C++
952       * @c struct or @c class layout or implementation which it may be compatible       * @c struct or @c class layout or implementation which it may be compatible
953       * with. For primitive, fundamental C/C++ data types the return value of       * with. For primitive, fundamental C/C++ data types (including @c String
954       * this method has no meaning.       * objects) the return value of this method has no meaning.
955       *       *
956       * @see Archive::setVersion() and Archive::setMinVersion() for more details       * @see Archive::setVersion() and Archive::setMinVersion() for more details
957       *      about this overall topic.       *      about this overall topic.
# Line 1063  namespace Serialization { Line 1281  namespace Serialization {
1281          m_root = NO_UID;          m_root = NO_UID;
1282          m_isModified = false;          m_isModified = false;
1283          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1284          decode(m_rawData);          decode(data);
1285      }      }
1286    
1287      /** @brief Create and fill the archive with the given serialized raw C-buffer data.      /** @brief Create and fill the archive with the given serialized raw C-buffer data.
# Line 1130  namespace Serialization { Line 1348  namespace Serialization {
1348          String s;          String s;
1349          s += _encodeBlob(type.baseTypeName());          s += _encodeBlob(type.baseTypeName());
1350          s += _encodeBlob(type.customTypeName());          s += _encodeBlob(type.customTypeName());
1351            if (!type.customTypeName2().empty())
1352                s += _encodeBlob(type.customTypeName2());
1353          s += _encodeBlob(ToString(type.size()));          s += _encodeBlob(ToString(type.size()));
1354          s += _encodeBlob(ToString(type.isPointer()));          s += _encodeBlob(ToString(type.isPointer()));
1355          return _encodeBlob(s);          return _encodeBlob(s);
# Line 1199  namespace Serialization { Line 1419  namespace Serialization {
1419                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1420              } else if (type.isBool()) {              } else if (type.isBool()) {
1421                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1422                } else if (type.isString()) {
1423                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1424              } else {              } else {
1425                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1426              }              }
   
1427          }          }
1428          return s;          return s;
1429      }      }
1430    
1431      template<typename T>      template<typename T>
1432        inline T _stringToNumber(const String& s) {
1433            assert(false /* String cast to unknown primitive number type */);
1434        }
1435    
1436        template<>
1437        inline int64_t _stringToNumber(const String& s) {
1438            return atoll(s.c_str());
1439        }
1440    
1441        template<>
1442        inline double _stringToNumber(const String& s) {
1443            return atof(s.c_str());
1444        }
1445    
1446        template<>
1447        inline bool _stringToNumber(const String& s) {
1448            return (bool) atoll(s.c_str());
1449        }
1450    
1451        template<typename T>
1452      static T _primitiveObjectValueToNumber(const Object& obj) {      static T _primitiveObjectValueToNumber(const Object& obj) {
1453          T value = 0;          T value = 0;
1454          const DataType& type = obj.type();          const DataType& type = obj.type();
# Line 1249  namespace Serialization { Line 1490  namespace Serialization {
1490                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1491              } else if (type.isBool()) {              } else if (type.isBool()) {
1492                  value = (T)*(bool*)ptr;                  value = (T)*(bool*)ptr;
1493                } else if (type.isString()) {
1494                    value = _stringToNumber<T>(
1495                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1496                    );
1497              } else {              } else {
1498                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1499              }              }
# Line 1282  namespace Serialization { Line 1527  namespace Serialization {
1527          return _encodeBlob(s);          return _encodeBlob(s);
1528      }      }
1529    
1530        /*
1531         * Srx format history:
1532         * - 1.0: Initial version.
1533         * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1534         *        2nd custom type name (e.g. "Map" types which always contain two
1535         *        user defined types).
1536         */
1537      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1538      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1539    
1540      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1541          String s;          String s;
# Line 1409  namespace Serialization { Line 1661  namespace Serialization {
1661          return s;          return s;
1662      }      }
1663    
1664        static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1665            String s = _popStringBlob(p, end);
1666            rawData.resize(s.length() + 1);
1667            strcpy((char*)&rawData[0], &s[0]);
1668        }
1669    
1670      static time_t _popTimeBlob(const char*& p, const char* end) {      static time_t _popTimeBlob(const char*& p, const char* end) {
1671          const uint64_t i = _popIntBlob<uint64_t>(p, end);          const uint64_t i = _popIntBlob<uint64_t>(p, end);
1672          return (time_t) i;          return (time_t) i;
1673      }      }
1674    
1675      DataType _popDataTypeBlob(const char*& p, const char* end) {      static DataType _popDataTypeBlob(const char*& p, const char* end) {
1676          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1677          p   = blob.p;          p   = blob.p;
1678          end = blob.end;          end = blob.end;
# Line 1422  namespace Serialization { Line 1680  namespace Serialization {
1680          DataType type;          DataType type;
1681          type.m_baseTypeName   = _popStringBlob(p, end);          type.m_baseTypeName   = _popStringBlob(p, end);
1682          type.m_customTypeName = _popStringBlob(p, end);          type.m_customTypeName = _popStringBlob(p, end);
1683            if (type.isMap())
1684                type.m_customTypeName2 = _popStringBlob(p, end);
1685          type.m_size           = _popIntBlob<int>(p, end);          type.m_size           = _popIntBlob<int>(p, end);
1686          type.m_isPointer      = _popIntBlob<bool>(p, end);          type.m_isPointer      = _popIntBlob<bool>(p, end);
1687          return type;          return type;
# Line 1465  namespace Serialization { Line 1725  namespace Serialization {
1725          if (p >= end) return m;          if (p >= end) return m;
1726    
1727          m.m_uid    = _popUIDBlob(p, end);          m.m_uid    = _popUIDBlob(p, end);
1728          m.m_offset = _popIntBlob<size_t>(p, end);          m.m_offset = _popIntBlob<ssize_t>(p, end);
1729          m.m_name   = _popStringBlob(p, end);          m.m_name   = _popStringBlob(p, end);
1730          m.m_type   = _popDataTypeBlob(p, end);          m.m_type   = _popDataTypeBlob(p, end);
1731          assert(m.type());          assert(m.type());
# Line 1527  namespace Serialization { Line 1787  namespace Serialization {
1787                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1788              } else if (type.isBool()) {              } else if (type.isBool()) {
1789                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1790                } else if (type.isString()) {
1791                    _popStringBlob(p, end, obj.m_data);
1792              } else {              } else {
1793                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1794              }              }
# Line 2067  namespace Serialization { Line 2329  namespace Serialization {
2329          m_isModified = true;          m_isModified = true;
2330      }      }
2331    
2332        /** @brief Set new textual string for given String object.
2333         *
2334         * Sets the new textual string @a value to the given String @a object.
2335         *
2336         * @param object - the String object to be changed
2337         * @param value - the new textual string to be assigned to the @a object
2338         * @throws Exception if @a object is not a String type.
2339         */
2340        void Archive::setStringValue(Object& object, String value) {
2341            if (!object) return;
2342            if (!object.type().isString())
2343                throw Exception("Not a String data type");
2344            Object* pObject = &object;
2345            if (object.type().isPointer()) {
2346                Object& obj = objectByUID(object.uid(1));
2347                if (!obj) return;
2348                pObject = &obj;
2349            }
2350            pObject->m_data.resize(value.length() + 1);
2351            char* ptr = (char*) &pObject->m_data[0];
2352            strcpy(ptr, &value[0]);
2353            m_isModified = true;
2354        }
2355    
2356      /** @brief Automatically cast and assign appropriate value to object.      /** @brief Automatically cast and assign appropriate value to object.
2357       *       *
2358       * This method automatically converts the given @a value from textual string       * This method automatically converts the given @a value from textual string
# Line 2095  namespace Serialization { Line 2381  namespace Serialization {
2381                  setBoolValue(object, false);                  setBoolValue(object, false);
2382              else              else
2383                  setBoolValue(object, atof(value.c_str()));                  setBoolValue(object, atof(value.c_str()));
2384          } else if (type.isEnum())          } else if (type.isString())
2385                setStringValue(object, value);
2386            else if (type.isEnum())
2387              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2388          else          else
2389              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
# Line 2192  namespace Serialization { Line 2480  namespace Serialization {
2480          return _primitiveObjectValueToNumber<bool>(*pObject);          return _primitiveObjectValueToNumber<bool>(*pObject);
2481      }      }
2482    
2483        Archive::operation_t Archive::operation() const {
2484            return m_operation;
2485        }
2486    
2487      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2488      // *      // *
2489    
# Line 2213  namespace Serialization { Line 2505  namespace Serialization {
2505          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2506      }      }
2507    
2508        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2509            assert(dstObj.type().isString());
2510            assert(dstObj.type() == srcObj.type());
2511            String* pDst = (String*)(void*)dstObj.uid().id;
2512            *pDst = (String) (const char*) &srcObj.rawData()[0];
2513        }
2514    
2515        void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2516            assert(dstObj.type().isArray());
2517            assert(dstObj.type() == srcObj.type());
2518            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2519        }
2520    
2521        void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2522            assert(dstObj.type().isSet());
2523            assert(dstObj.type() == srcObj.type());
2524            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2525        }
2526    
2527        void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2528            assert(dstObj.type().isMap());
2529            assert(dstObj.type() == srcObj.type());
2530            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2531        }
2532    
2533      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2534          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2535          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 2239  namespace Serialization { Line 2556  namespace Serialization {
2556          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2557    
2558          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2559              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2560                    syncString(dstObj, srcObj);
2561                else
2562                    syncPrimitive(dstObj, srcObj);
2563              return; // end of recursion              return; // end of recursion
2564          }          }
2565    
2566            if (dstObj.type().isArray()) {
2567                syncArray(dstObj, srcObj);
2568                return;
2569            }
2570    
2571            if (dstObj.type().isSet()) {
2572                syncSet(dstObj, srcObj);
2573                return;
2574            }
2575    
2576            if (dstObj.type().isMap()) {
2577                syncMap(dstObj, srcObj);
2578                return;
2579            }
2580    
2581          if (dstObj.type().isPointer()) {          if (dstObj.type().isPointer()) {
2582              syncPointer(dstObj, srcObj);              syncPointer(dstObj, srcObj);
2583              return;              return;

Legend:
Removed from v.3333  
changed lines
  Added in v.3777

  ViewVC Help
Powered by ViewVC