/[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 3198 by schoenebeck, Sun May 21 12:46:05 2017 UTC revision 3778 by schoenebeck, Sun May 24 11:20:11 2020 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2017 Christian Schoenebeck                              *   *   Copyright (C) 2017-2020 Christian Schoenebeck                         *
4   *                      <cuse@users.sourceforge.net>                       *   *                           <cuse@users.sourceforge.net>                  *
5   *                                                                         *   *                                                                         *
6   *   This library is part of libgig.                                       *   *   This library is part of libgig.                                       *
7   *                                                                         *   *                                                                         *
# Line 21  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    // enable implementation specific declarations in Serialization.h required to
25    // build this C++ unit, which should be ignored in the public API though
26    #define LIBGIG_SERIALIZATION_INTERNAL 1
27    
28  #include "Serialization.h"  #include "Serialization.h"
29    
30  #include <iostream>  #include <iostream>
 #include <assert.h>  
31  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
32  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
33  #include <cxxabi.h>  #ifdef _MSC_VER
34    # include <windows.h>
35    # include <dbghelp.h>
36    #else
37    # include <cxxabi.h>
38    #endif
39  #include "helper.h"  #include "helper.h"
40    
41  #define LIBGIG_EPOCH_TIME ((time_t)0)  #define LIBGIG_EPOCH_TIME ((time_t)0)
# Line 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 250  namespace Serialization { Line 354  namespace Serialization {
354       * characteristic is compared as well. So a @c double type and @c double*       * characteristic is compared as well. So a @c double type and @c double*
355       * type are also considered to be not equal data types and hence this method       * type are also considered to be not equal data types and hence this method
356       * would return @c false.       * would return @c false.
357         *
358         * As an exception here, classes and structs with the same class/struct name
359         * but different sizes are also considered to be "equal". This relaxed
360         * requirement is necessary to retain backward compatiblity to older
361         * versions of the same native C++ classes/structs.
362       */       */
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_size           == other.m_size &&                 m_customTypeName2 == other.m_customTypeName2 &&
367                   (m_size == other.m_size || (isClass() && other.isClass())) &&
368                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
369      }      }
370    
# Line 281  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 321  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 353  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 390  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 420  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 502  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 568  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 664  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 714  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 727  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 1058  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 1123  namespace Serialization { Line 1346  namespace Serialization {
1346    
1347      static String _encode(const DataType& type) {      static String _encode(const DataType& type) {
1348          String s;          String s;
1349    
1350            // Srx v1.0 format (mandatory):
1351          s += _encodeBlob(type.baseTypeName());          s += _encodeBlob(type.baseTypeName());
1352          s += _encodeBlob(type.customTypeName());          s += _encodeBlob(type.customTypeName());
1353          s += _encodeBlob(ToString(type.size()));          s += _encodeBlob(ToString(type.size()));
1354          s += _encodeBlob(ToString(type.isPointer()));          s += _encodeBlob(ToString(type.isPointer()));
1355    
1356            // Srx v1.1 format:
1357            s += _encodeBlob(type.customTypeName2());
1358    
1359          return _encodeBlob(s);          return _encodeBlob(s);
1360      }      }
1361    
# Line 1194  namespace Serialization { Line 1423  namespace Serialization {
1423                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1424              } else if (type.isBool()) {              } else if (type.isBool()) {
1425                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1426                } else if (type.isString()) {
1427                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1428              } else {              } else {
1429                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1430              }              }
   
1431          }          }
1432          return s;          return s;
1433      }      }
1434    
1435      template<typename T>      template<typename T>
1436        inline T _stringToNumber(const String& s) {
1437            assert(false /* String cast to unknown primitive number type */);
1438        }
1439    
1440        template<>
1441        inline int64_t _stringToNumber(const String& s) {
1442            return atoll(s.c_str());
1443        }
1444    
1445        template<>
1446        inline double _stringToNumber(const String& s) {
1447            return atof(s.c_str());
1448        }
1449    
1450        template<>
1451        inline bool _stringToNumber(const String& s) {
1452            return (bool) atoll(s.c_str());
1453        }
1454    
1455        template<typename T>
1456      static T _primitiveObjectValueToNumber(const Object& obj) {      static T _primitiveObjectValueToNumber(const Object& obj) {
1457          T value = 0;          T value = 0;
1458          const DataType& type = obj.type();          const DataType& type = obj.type();
# Line 1244  namespace Serialization { Line 1494  namespace Serialization {
1494                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1495              } else if (type.isBool()) {              } else if (type.isBool()) {
1496                  value = (T)*(bool*)ptr;                  value = (T)*(bool*)ptr;
1497                } else if (type.isString()) {
1498                    value = _stringToNumber<T>(
1499                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1500                    );
1501              } else {              } else {
1502                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1503              }              }
# Line 1277  namespace Serialization { Line 1531  namespace Serialization {
1531          return _encodeBlob(s);          return _encodeBlob(s);
1532      }      }
1533    
1534        /*
1535         * Srx format history:
1536         * - 1.0: Initial version.
1537         * - 1.1: Adds "String", "Array", "Set" and "Map" data types and an optional
1538         *        2nd custom type name (e.g. "Map" types which always contain two
1539         *        user defined types).
1540         */
1541      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1542      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1543    
1544      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1545          String s;          String s;
# Line 1404  namespace Serialization { Line 1665  namespace Serialization {
1665          return s;          return s;
1666      }      }
1667    
1668        static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1669            String s = _popStringBlob(p, end);
1670            rawData.resize(s.length() + 1);
1671            strcpy((char*)&rawData[0], &s[0]);
1672        }
1673    
1674      static time_t _popTimeBlob(const char*& p, const char* end) {      static time_t _popTimeBlob(const char*& p, const char* end) {
1675          const uint64_t i = _popIntBlob<uint64_t>(p, end);          const uint64_t i = _popIntBlob<uint64_t>(p, end);
1676          return (time_t) i;          return (time_t) i;
1677      }      }
1678    
1679      DataType _popDataTypeBlob(const char*& p, const char* end) {      static DataType _popDataTypeBlob(const char*& p, const char* end) {
1680          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1681          p   = blob.p;          p   = blob.p;
1682          end = blob.end;          end = blob.end;
1683    
1684          DataType type;          DataType type;
1685    
1686            // Srx v1.0 format (mandatory):
1687          type.m_baseTypeName   = _popStringBlob(p, end);          type.m_baseTypeName   = _popStringBlob(p, end);
1688          type.m_customTypeName = _popStringBlob(p, end);          type.m_customTypeName = _popStringBlob(p, end);
1689          type.m_size           = _popIntBlob<int>(p, end);          type.m_size           = _popIntBlob<int>(p, end);
1690          type.m_isPointer      = _popIntBlob<bool>(p, end);          type.m_isPointer      = _popIntBlob<bool>(p, end);
1691    
1692            // Srx v1.1 format (optional):
1693            if (p < end)
1694                type.m_customTypeName2 = _popStringBlob(p, end);
1695    
1696          return type;          return type;
1697      }      }
1698    
# Line 1460  namespace Serialization { Line 1734  namespace Serialization {
1734          if (p >= end) return m;          if (p >= end) return m;
1735    
1736          m.m_uid    = _popUIDBlob(p, end);          m.m_uid    = _popUIDBlob(p, end);
1737          m.m_offset = _popIntBlob<size_t>(p, end);          m.m_offset = _popIntBlob<ssize_t>(p, end);
1738          m.m_name   = _popStringBlob(p, end);          m.m_name   = _popStringBlob(p, end);
1739          m.m_type   = _popDataTypeBlob(p, end);          m.m_type   = _popDataTypeBlob(p, end);
1740          assert(m.type());          assert(m.type());
# Line 1522  namespace Serialization { Line 1796  namespace Serialization {
1796                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1797              } else if (type.isBool()) {              } else if (type.isBool()) {
1798                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1799                } else if (type.isString()) {
1800                    _popStringBlob(p, end, obj.m_data);
1801              } else {              } else {
1802                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1803              }              }
# Line 2062  namespace Serialization { Line 2338  namespace Serialization {
2338          m_isModified = true;          m_isModified = true;
2339      }      }
2340    
2341        /** @brief Set new textual string for given String object.
2342         *
2343         * Sets the new textual string @a value to the given String @a object.
2344         *
2345         * @param object - the String object to be changed
2346         * @param value - the new textual string to be assigned to the @a object
2347         * @throws Exception if @a object is not a String type.
2348         */
2349        void Archive::setStringValue(Object& object, String value) {
2350            if (!object) return;
2351            if (!object.type().isString())
2352                throw Exception("Not a String data type");
2353            Object* pObject = &object;
2354            if (object.type().isPointer()) {
2355                Object& obj = objectByUID(object.uid(1));
2356                if (!obj) return;
2357                pObject = &obj;
2358            }
2359            pObject->m_data.resize(value.length() + 1);
2360            char* ptr = (char*) &pObject->m_data[0];
2361            strcpy(ptr, &value[0]);
2362            m_isModified = true;
2363        }
2364    
2365      /** @brief Automatically cast and assign appropriate value to object.      /** @brief Automatically cast and assign appropriate value to object.
2366       *       *
2367       * This method automatically converts the given @a value from textual string       * This method automatically converts the given @a value from textual string
# Line 2090  namespace Serialization { Line 2390  namespace Serialization {
2390                  setBoolValue(object, false);                  setBoolValue(object, false);
2391              else              else
2392                  setBoolValue(object, atof(value.c_str()));                  setBoolValue(object, atof(value.c_str()));
2393          } else if (type.isEnum())          } else if (type.isString())
2394                setStringValue(object, value);
2395            else if (type.isEnum())
2396              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2397          else          else
2398              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
# Line 2187  namespace Serialization { Line 2489  namespace Serialization {
2489          return _primitiveObjectValueToNumber<bool>(*pObject);          return _primitiveObjectValueToNumber<bool>(*pObject);
2490      }      }
2491    
2492        Archive::operation_t Archive::operation() const {
2493            return m_operation;
2494        }
2495    
2496      // *************** Archive::Syncer ***************      // *************** Archive::Syncer ***************
2497      // *      // *
2498    
# Line 2208  namespace Serialization { Line 2514  namespace Serialization {
2514          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2515      }      }
2516    
2517        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2518            assert(dstObj.type().isString());
2519            assert(dstObj.type() == srcObj.type());
2520            String* pDst = (String*)(void*)dstObj.uid().id;
2521            *pDst = (String) (const char*) &srcObj.rawData()[0];
2522        }
2523    
2524        void Archive::Syncer::syncArray(const Object& dstObj, const Object& srcObj) {
2525            assert(dstObj.type().isArray());
2526            assert(dstObj.type() == srcObj.type());
2527            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2528        }
2529    
2530        void Archive::Syncer::syncSet(const Object& dstObj, const Object& srcObj) {
2531            assert(dstObj.type().isSet());
2532            assert(dstObj.type() == srcObj.type());
2533            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2534        }
2535    
2536        void Archive::Syncer::syncMap(const Object& dstObj, const Object& srcObj) {
2537            assert(dstObj.type().isMap());
2538            assert(dstObj.type() == srcObj.type());
2539            dstObj.m_sync(const_cast<Object&>(dstObj), srcObj, this);
2540        }
2541    
2542      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2543          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2544          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 2234  namespace Serialization { Line 2565  namespace Serialization {
2565          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2566    
2567          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2568              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2569                    syncString(dstObj, srcObj);
2570                else
2571                    syncPrimitive(dstObj, srcObj);
2572              return; // end of recursion              return; // end of recursion
2573          }          }
2574    
2575            if (dstObj.type().isArray()) {
2576                syncArray(dstObj, srcObj);
2577                return;
2578            }
2579    
2580            if (dstObj.type().isSet()) {
2581                syncSet(dstObj, srcObj);
2582                return;
2583            }
2584    
2585            if (dstObj.type().isMap()) {
2586                syncMap(dstObj, srcObj);
2587                return;
2588            }
2589    
2590          if (dstObj.type().isPointer()) {          if (dstObj.type().isPointer()) {
2591              syncPointer(dstObj, srcObj);              syncPointer(dstObj, srcObj);
2592              return;              return;

Legend:
Removed from v.3198  
changed lines
  Added in v.3778

  ViewVC Help
Powered by ViewVC