/[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 3476 by schoenebeck, Wed Feb 20 19:12:49 2019 UTC revision 3773 by schoenebeck, Tue May 19 14:28:20 2020 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2017-2019 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.                                       *
# Line 28  Line 28 
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  #ifdef _MSC_VER  #ifdef _MSC_VER
# Line 71  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 85  namespace Serialization { Line 84  namespace Serialization {
84          m_isPointer = false;          m_isPointer = false;
85      }      }
86    
87        /** @brief Constructs a valid DataType object.
88         *
89         * Initializes this object as "valid" DataType object, with specific and
90         * useful data type information.
91         *
92         * This is a protected constructor which should not be called directly by
93         * applications, as its argument list is somewhat implementation specific
94         * and might change at any time. Applications should call the static
95         * function DataType::dataTypeOf() instead.
96         *
97         * @param isPointer - whether pointer type (i.e. a simple memory address)
98         * @param size - native size of data type in bytes (i.e. according to
99         *               @c sizeof() C/C++ keyword)
100         * @param baseType - this framework's internal name for specifying the base
101         *                   type in a coarse way, which must be either one of:
102         *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",
103         *                   "int64", "uint64", "bool", "real32", "real64",
104         *                   "String", "enum", "union" or "class"
105         * @param customType - this is only used for base types "enum", "union" or
106         *                     "class", in which case this identifies the user
107         *                     defined type name (e.g. "Foo" for @c class @c Foo ),
108         *                     for all other types this is empty
109         */
110      DataType::DataType(bool isPointer, int size, String baseType, String customType) {      DataType::DataType(bool isPointer, int size, String baseType, String customType) {
111          m_size = size;          m_size = size;
112          m_isPointer = isPointer;          m_isPointer = isPointer;
# Line 119  namespace Serialization { Line 141  namespace Serialization {
141       *       *
142       * 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
143       * (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
144       * type.       * type, with one exception: @c String objects are handled by this framework
145         * as if they were a primitive type.
146       *       *
147       * Note that in the following example:       * Note that in the following example:
148       * @code       * @code
# Line 145  namespace Serialization { Line 168  namespace Serialization {
168       * (this DataType instance is reflecting) is a primitive, fundamental C/C++       * (this DataType instance is reflecting) is a primitive, fundamental C/C++
169       * data type. Those are fundamental data types which are already predefined       * data type. Those are fundamental data types which are already predefined
170       * 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,
171       * @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
172       * including pointers to user defined types like:       * @c int*, @c double**, but including pointers to user defined types like:
173       * @code       * @code
174       * struct Foo {       * struct Foo {
175       *     int  a;       *     int  a;
# Line 163  namespace Serialization { Line 186  namespace Serialization {
186          return !isClass();          return !isClass();
187      }      }
188    
189        /** @brief Whether this is a C++ @c String data type.
190         *
191         * Returns @c true if the respective native C/C++ object, member or variable
192         * (this DataType instance is reflecting) is a C++ @c String object (a.k.a.
193         * @c std::string from the C++ STL).
194         *
195         * Note that this framework handles @c String objects as if they were a
196         * fundamental, primitive C/C++ data type, so @c isPrimitive() returns
197         * @c true for strings.
198         */
199        bool DataType::isString() const {
200            return m_baseTypeName == "String";
201        }
202    
203      /** @brief Whether this is an integer C/C++ data type.      /** @brief Whether this is an integer C/C++ data type.
204       *       *
205       * 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 403  namespace Serialization { Line 440  namespace Serialization {
440       * In the latter example @c customTypeName(true) would return for both       * In the latter example @c customTypeName(true) would return for both
441       * @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.
442       *       *
443         * @b Windows: please note that the current implementation of this method
444         * on Windows is @b not thread safe!
445         *
446       * @see isPointer(), baseTypeName()       * @see isPointer(), baseTypeName()
447       */       */
448      String DataType::customTypeName(bool demangle) const {      String DataType::customTypeName(bool demangle) const {
# Line 411  namespace Serialization { Line 451  namespace Serialization {
451          const size_t MAXLENGTH = 1024;          const size_t MAXLENGTH = 1024;
452          char result[MAXLENGTH];          char result[MAXLENGTH];
453    
454            //FIXME: calling UnDecorateSymbolName() is not thread safe!
455          //Skip the first char          //Skip the first char
456          size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);          size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
457          if (size)          if (size)
# Line 742  namespace Serialization { Line 783  namespace Serialization {
783       * 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
784       * 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
785       * or @c class layout or implementation. For primitive, fundamental C/C++       * or @c class layout or implementation. For primitive, fundamental C/C++
786       * data types the return value of this method has no meaning.       * data types (including @c String objects) the return value of this method
787         * has no meaning.
788       *       *
789       * @see Archive::setVersion() for more details about this overall topic.       * @see Archive::setVersion() for more details about this overall topic.
790       */       */
# Line 755  namespace Serialization { Line 797  namespace Serialization {
797       * 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
798       * 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++
799       * @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
800       * with. For primitive, fundamental C/C++ data types the return value of       * with. For primitive, fundamental C/C++ data types (including @c String
801       * this method has no meaning.       * objects) the return value of this method has no meaning.
802       *       *
803       * @see Archive::setVersion() and Archive::setMinVersion() for more details       * @see Archive::setVersion() and Archive::setMinVersion() for more details
804       *      about this overall topic.       *      about this overall topic.
# Line 1086  namespace Serialization { Line 1128  namespace Serialization {
1128          m_root = NO_UID;          m_root = NO_UID;
1129          m_isModified = false;          m_isModified = false;
1130          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1131          decode(m_rawData);          decode(data);
1132      }      }
1133    
1134      /** @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 1222  namespace Serialization { Line 1264  namespace Serialization {
1264                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1265              } else if (type.isBool()) {              } else if (type.isBool()) {
1266                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1267                } else if (type.isString()) {
1268                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1269              } else {              } else {
1270                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1271              }              }
# Line 1231  namespace Serialization { Line 1275  namespace Serialization {
1275      }      }
1276    
1277      template<typename T>      template<typename T>
1278        inline T _stringToNumber(const String& s) {
1279            assert(false /* String cast to unknown primitive number type */);
1280        }
1281    
1282        template<>
1283        inline int64_t _stringToNumber(const String& s) {
1284            return atoll(s.c_str());
1285        }
1286    
1287        template<>
1288        inline double _stringToNumber(const String& s) {
1289            return atof(s.c_str());
1290        }
1291    
1292        template<>
1293        inline bool _stringToNumber(const String& s) {
1294            return (bool) atoll(s.c_str());
1295        }
1296    
1297        template<typename T>
1298      static T _primitiveObjectValueToNumber(const Object& obj) {      static T _primitiveObjectValueToNumber(const Object& obj) {
1299          T value = 0;          T value = 0;
1300          const DataType& type = obj.type();          const DataType& type = obj.type();
# Line 1272  namespace Serialization { Line 1336  namespace Serialization {
1336                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1337              } else if (type.isBool()) {              } else if (type.isBool()) {
1338                  value = (T)*(bool*)ptr;                  value = (T)*(bool*)ptr;
1339                } else if (type.isString()) {
1340                    value = _stringToNumber<T>(
1341                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1342                    );
1343              } else {              } else {
1344                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1345              }              }
# Line 1305  namespace Serialization { Line 1373  namespace Serialization {
1373          return _encodeBlob(s);          return _encodeBlob(s);
1374      }      }
1375    
1376        /*
1377         * Srx format history:
1378         * - 1.0: Initial version.
1379         * - 1.1: Adds "String" data type.
1380         */
1381      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1382      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1383    
1384      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1385          String s;          String s;
# Line 1432  namespace Serialization { Line 1505  namespace Serialization {
1505          return s;          return s;
1506      }      }
1507    
1508        static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1509            String s = _popStringBlob(p, end);
1510            rawData.resize(s.length() + 1);
1511            strcpy((char*)&rawData[0], &s[0]);
1512        }
1513    
1514      static time_t _popTimeBlob(const char*& p, const char* end) {      static time_t _popTimeBlob(const char*& p, const char* end) {
1515          const uint64_t i = _popIntBlob<uint64_t>(p, end);          const uint64_t i = _popIntBlob<uint64_t>(p, end);
1516          return (time_t) i;          return (time_t) i;
# Line 1550  namespace Serialization { Line 1629  namespace Serialization {
1629                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1630              } else if (type.isBool()) {              } else if (type.isBool()) {
1631                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1632                } else if (type.isString()) {
1633                    _popStringBlob(p, end, obj.m_data);
1634              } else {              } else {
1635                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1636              }              }
# Line 2090  namespace Serialization { Line 2171  namespace Serialization {
2171          m_isModified = true;          m_isModified = true;
2172      }      }
2173    
2174        /** @brief Set new textual string for given String object.
2175         *
2176         * Sets the new textual string @a value to the given String @a object.
2177         *
2178         * @param object - the String object to be changed
2179         * @param value - the new textual string to be assigned to the @a object
2180         * @throws Exception if @a object is not a String type.
2181         */
2182        void Archive::setStringValue(Object& object, String value) {
2183            if (!object) return;
2184            if (!object.type().isString())
2185                throw Exception("Not a String data type");
2186            Object* pObject = &object;
2187            if (object.type().isPointer()) {
2188                Object& obj = objectByUID(object.uid(1));
2189                if (!obj) return;
2190                pObject = &obj;
2191            }
2192            pObject->m_data.resize(value.length() + 1);
2193            char* ptr = (char*) &pObject->m_data[0];
2194            strcpy(ptr, &value[0]);
2195            m_isModified = true;
2196        }
2197    
2198      /** @brief Automatically cast and assign appropriate value to object.      /** @brief Automatically cast and assign appropriate value to object.
2199       *       *
2200       * This method automatically converts the given @a value from textual string       * This method automatically converts the given @a value from textual string
# Line 2118  namespace Serialization { Line 2223  namespace Serialization {
2223                  setBoolValue(object, false);                  setBoolValue(object, false);
2224              else              else
2225                  setBoolValue(object, atof(value.c_str()));                  setBoolValue(object, atof(value.c_str()));
2226          } else if (type.isEnum())          } else if (type.isString())
2227                setStringValue(object, value);
2228            else if (type.isEnum())
2229              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2230          else          else
2231              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
# Line 2236  namespace Serialization { Line 2343  namespace Serialization {
2343          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2344      }      }
2345    
2346        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2347            assert(dstObj.type().isString());
2348            assert(dstObj.type() == srcObj.type());
2349            String* pDst = (String*)(void*)dstObj.uid().id;
2350            *pDst = (String) (const char*) &srcObj.rawData()[0];
2351        }
2352    
2353      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2354          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2355          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 2262  namespace Serialization { Line 2376  namespace Serialization {
2376          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2377    
2378          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2379              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2380                    syncString(dstObj, srcObj);
2381                else
2382                    syncPrimitive(dstObj, srcObj);
2383              return; // end of recursion              return; // end of recursion
2384          }          }
2385    

Legend:
Removed from v.3476  
changed lines
  Added in v.3773

  ViewVC Help
Powered by ViewVC