/[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 3185 by schoenebeck, Wed May 17 15:42:58 2017 UTC revision 3771 by schoenebeck, Sun May 17 17:14:31 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>
31  #include <assert.h>  #include <assert.h>
32  #include <string.h> // for memcpy()  #include <string.h> // for memcpy()
33  #include <stdlib.h> // for atof()  #include <stdlib.h> // for atof()
34  #include <cxxabi.h>  #ifdef _MSC_VER
35    # include <windows.h>
36    # include <dbghelp.h>
37    #else
38    # include <cxxabi.h>
39    #endif
40  #include "helper.h"  #include "helper.h"
41    
42  #define LIBGIG_EPOCH_TIME ((time_t)0)  #define LIBGIG_EPOCH_TIME ((time_t)0)
# Line 63  namespace Serialization { Line 71  namespace Serialization {
71      // *************** DataType ***************      // *************** DataType ***************
72      // *      // *
73    
74      /** @brief Default constructor.      /** @brief Default constructor (as "invalid" DataType).
75       *       *
76       * Initializes a DataType object as being an "invalid" DataType object.       * Initializes a DataType object as being an "invalid" DataType object.
77       * 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 85  namespace Serialization {
85          m_isPointer = false;          m_isPointer = false;
86      }      }
87    
88        /** @brief Constructs a valid DataType object.
89         *
90         * Initializes this object as "valid" DataType object, with specific and
91         * useful data type information.
92         *
93         * This is a protected constructor which should not be called directly by
94         * applications, as its argument list is somewhat implementation specific
95         * and might change at any time. Applications should call the static
96         * function DataType::dataTypeOf() instead.
97         *
98         * @param isPointer - whether pointer type (i.e. a simple memory address)
99         * @param size - native size of data type in bytes (i.e. according to
100         *               @c sizeof() C/C++ keyword)
101         * @param baseType - this framework's internal name for specifying the base
102         *                   type in a coarse way, which must be either one of:
103         *                   "int8", "uint8", "int16", "uint16", "int32", "uint32",
104         *                   "int64", "uint64", "bool", "real32", "real64",
105         *                   "String", "enum", "union" or "class"
106         * @param customType - this is only used for base types "enum", "union" or
107         *                     "class", in which case this identifies the user
108         *                     defined type name (e.g. "Foo" for @c class @c Foo ),
109         *                     for all other types this is empty
110         */
111      DataType::DataType(bool isPointer, int size, String baseType, String customType) {      DataType::DataType(bool isPointer, int size, String baseType, String customType) {
112          m_size = size;          m_size = size;
113          m_isPointer = isPointer;          m_isPointer = isPointer;
# Line 111  namespace Serialization { Line 142  namespace Serialization {
142       *       *
143       * 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
144       * (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
145       * type.       * type, with one exception: @c String objects are handled by this framework
146         * as if they were a primitive type.
147       *       *
148       * Note that in the following example:       * Note that in the following example:
149       * @code       * @code
# Line 137  namespace Serialization { Line 169  namespace Serialization {
169       * (this DataType instance is reflecting) is a primitive, fundamental C/C++       * (this DataType instance is reflecting) is a primitive, fundamental C/C++
170       * data type. Those are fundamental data types which are already predefined       * data type. Those are fundamental data types which are already predefined
171       * 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,
172       * @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
173       * including pointers to user defined types like:       * @c int*, @c double**, but including pointers to user defined types like:
174       * @code       * @code
175       * struct Foo {       * struct Foo {
176       *     int  a;       *     int  a;
# Line 155  namespace Serialization { Line 187  namespace Serialization {
187          return !isClass();          return !isClass();
188      }      }
189    
190        /** @brief Whether this is a C++ @c String data type.
191         *
192         * Returns @c true if the respective native C/C++ object, member or variable
193         * (this DataType instance is reflecting) is a C++ @c String object (a.k.a.
194         * @c std::string from the C++ STL).
195         *
196         * Note that this framework handles @c String objects as if they were a
197         * fundamental, primitive C/C++ data type, so @c isPrimitive() returns
198         * @c true for strings.
199         */
200        bool DataType::isString() const {
201            return m_baseTypeName == "String";
202        }
203    
204      /** @brief Whether this is an integer C/C++ data type.      /** @brief Whether this is an integer C/C++ data type.
205       *       *
206       * 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 296  namespace Serialization {
296       * 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*
297       * 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
298       * would return @c false.       * would return @c false.
299         *
300         * As an exception here, classes and structs with the same class/struct name
301         * but different sizes are also considered to be "equal". This relaxed
302         * requirement is necessary to retain backward compatiblity to older
303         * versions of the same native C++ classes/structs.
304       */       */
305      bool DataType::operator==(const DataType& other) const {      bool DataType::operator==(const DataType& other) const {
306          return m_baseTypeName   == other.m_baseTypeName &&          return m_baseTypeName   == other.m_baseTypeName &&
307                 m_customTypeName == other.m_customTypeName &&                 m_customTypeName == other.m_customTypeName &&
308                 m_size           == other.m_size &&                 (m_size == other.m_size || (isClass() && other.isClass())) &&
309                 m_isPointer      == other.m_isPointer;                 m_isPointer      == other.m_isPointer;
310      }      }
311    
# Line 281  namespace Serialization { Line 332  namespace Serialization {
332      bool DataType::operator<(const DataType& other) const {      bool DataType::operator<(const DataType& other) const {
333          return m_baseTypeName  < other.m_baseTypeName ||          return m_baseTypeName  < other.m_baseTypeName ||
334                (m_baseTypeName == other.m_baseTypeName &&                (m_baseTypeName == other.m_baseTypeName &&
335                 m_customTypeName  < other.m_customTypeName ||                (m_customTypeName  < other.m_customTypeName ||
336                (m_customTypeName == other.m_customTypeName &&                (m_customTypeName == other.m_customTypeName &&
337                 m_size  < other.m_size ||                (m_size  < other.m_size ||
338                (m_size == other.m_size &&                (m_size == other.m_size &&
339                 m_isPointer < other.m_isPointer)));                 m_isPointer < other.m_isPointer)))));
340      }      }
341    
342      /** @brief Greater than comparison.      /** @brief Greater than comparison.
# Line 390  namespace Serialization { Line 441  namespace Serialization {
441       * In the latter example @c customTypeName(true) would return for both       * In the latter example @c customTypeName(true) would return for both
442       * @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.
443       *       *
444         * @b Windows: please note that the current implementation of this method
445         * on Windows is @b not thread safe!
446         *
447       * @see isPointer(), baseTypeName()       * @see isPointer(), baseTypeName()
448       */       */
449      String DataType::customTypeName(bool demangle) const {      String DataType::customTypeName(bool demangle) const {
450          if (!demangle) return m_customTypeName;          if (!demangle) return m_customTypeName;
451    #ifdef _MSC_VER
452            const size_t MAXLENGTH = 1024;
453            char result[MAXLENGTH];
454    
455            //FIXME: calling UnDecorateSymbolName() is not thread safe!
456            //Skip the first char
457            size_t size = UnDecorateSymbolName(m_customTypeName.c_str() +1, result, MAXLENGTH, UNDNAME_32_BIT_DECODE | UNDNAME_NO_ARGUMENTS);
458            if (size)
459            {
460                return result;
461            }
462            return m_customTypeName;
463    #else
464          int status;          int status;
465          const char* result =          char* result =
466              abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);              abi::__cxa_demangle(m_customTypeName.c_str(), 0, 0, &status);
467          return (status == 0) ? result : m_customTypeName;          String sResult = result;
468            free(result);
469            return (status == 0) ? sResult : m_customTypeName;
470    #endif
471      }      }
472    
473      // *************** Member ***************      // *************** Member ***************
# Line 568  namespace Serialization { Line 638  namespace Serialization {
638      bool Member::operator<(const Member& other) const {      bool Member::operator<(const Member& other) const {
639          return m_uid  < other.m_uid ||          return m_uid  < other.m_uid ||
640                (m_uid == other.m_uid &&                (m_uid == other.m_uid &&
641                 m_offset  < other.m_offset ||                (m_offset  < other.m_offset ||
642                (m_offset == other.m_offset &&                (m_offset == other.m_offset &&
643                 m_name  < other.m_name ||                (m_name  < other.m_name ||
644                (m_name == other.m_name &&                (m_name == other.m_name &&
645                 m_type < other.m_type)));                 m_type < other.m_type)))));
646      }      }
647    
648      /** @brief Greater than comparison.      /** @brief Greater than comparison.
# Line 714  namespace Serialization { Line 784  namespace Serialization {
784       * 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
785       * 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
786       * or @c class layout or implementation. For primitive, fundamental C/C++       * or @c class layout or implementation. For primitive, fundamental C/C++
787       * data types the return value of this method has no meaning.       * data types (including @c String objects) the return value of this method
788         * has no meaning.
789       *       *
790       * @see Archive::setVersion() for more details about this overall topic.       * @see Archive::setVersion() for more details about this overall topic.
791       */       */
# Line 727  namespace Serialization { Line 798  namespace Serialization {
798       * 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
799       * 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++
800       * @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
801       * with. For primitive, fundamental C/C++ data types the return value of       * with. For primitive, fundamental C/C++ data types (including @c String
802       * this method has no meaning.       * objects) the return value of this method has no meaning.
803       *       *
804       * @see Archive::setVersion() and Archive::setMinVersion() for more details       * @see Archive::setVersion() and Archive::setMinVersion() for more details
805       *      about this overall topic.       *      about this overall topic.
# Line 1058  namespace Serialization { Line 1129  namespace Serialization {
1129          m_root = NO_UID;          m_root = NO_UID;
1130          m_isModified = false;          m_isModified = false;
1131          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;          m_timeCreated = m_timeModified = LIBGIG_EPOCH_TIME;
1132          decode(m_rawData);          decode(data);
1133      }      }
1134    
1135      /** @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 1194  namespace Serialization { Line 1265  namespace Serialization {
1265                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1266              } else if (type.isBool()) {              } else if (type.isBool()) {
1267                  s = ToString(*(bool*)ptr);                  s = ToString(*(bool*)ptr);
1268                } else if (type.isString()) {
1269                    s = obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr);
1270              } else {              } else {
1271                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1272              }              }
# Line 1203  namespace Serialization { Line 1276  namespace Serialization {
1276      }      }
1277    
1278      template<typename T>      template<typename T>
1279        inline T _stringToNumber(const String& s) {
1280            assert(false /* String cast to unknown primitive number type */);
1281        }
1282    
1283        template<>
1284        inline int64_t _stringToNumber(const String& s) {
1285            return atoll(s.c_str());
1286        }
1287    
1288        template<>
1289        inline double _stringToNumber(const String& s) {
1290            return atof(s.c_str());
1291        }
1292    
1293        template<>
1294        inline bool _stringToNumber(const String& s) {
1295            return (bool) atoll(s.c_str());
1296        }
1297    
1298        template<typename T>
1299      static T _primitiveObjectValueToNumber(const Object& obj) {      static T _primitiveObjectValueToNumber(const Object& obj) {
1300          T value = 0;          T value = 0;
1301          const DataType& type = obj.type();          const DataType& type = obj.type();
# Line 1244  namespace Serialization { Line 1337  namespace Serialization {
1337                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1338              } else if (type.isBool()) {              } else if (type.isBool()) {
1339                  value = (T)*(bool*)ptr;                  value = (T)*(bool*)ptr;
1340                } else if (type.isString()) {
1341                    value = _stringToNumber<T>(
1342                        obj.m_data.empty() ? *(String*)ptr : String((const char*)ptr)
1343                    );
1344              } else {              } else {
1345                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1346              }              }
# Line 1277  namespace Serialization { Line 1374  namespace Serialization {
1374          return _encodeBlob(s);          return _encodeBlob(s);
1375      }      }
1376    
1377        /*
1378         * Srx format history:
1379         * - 1.0: Initial version.
1380         * - 1.1: Adds "String" data type.
1381         */
1382      #define MAGIC_START "Srx1v"      #define MAGIC_START "Srx1v"
1383      #define ENCODING_FORMAT_MINOR_VERSION 0      #define ENCODING_FORMAT_MINOR_VERSION 1
1384    
1385      String Archive::_encodeRootBlob() {      String Archive::_encodeRootBlob() {
1386          String s;          String s;
# Line 1404  namespace Serialization { Line 1506  namespace Serialization {
1506          return s;          return s;
1507      }      }
1508    
1509        static void _popStringBlob(const char*& p, const char* end, RawData& rawData) {
1510            String s = _popStringBlob(p, end);
1511            rawData.resize(s.length() + 1);
1512            strcpy((char*)&rawData[0], &s[0]);
1513        }
1514    
1515      static time_t _popTimeBlob(const char*& p, const char* end) {      static time_t _popTimeBlob(const char*& p, const char* end) {
1516          const uint64_t i = _popIntBlob<uint64_t>(p, end);          const uint64_t i = _popIntBlob<uint64_t>(p, end);
1517          return (time_t) i;          return (time_t) i;
1518      }      }
1519    
1520      DataType _popDataTypeBlob(const char*& p, const char* end) {      static DataType _popDataTypeBlob(const char*& p, const char* end) {
1521          _Blob blob = _decodeBlob(p, end);          _Blob blob = _decodeBlob(p, end);
1522          p   = blob.p;          p   = blob.p;
1523          end = blob.end;          end = blob.end;
# Line 1522  namespace Serialization { Line 1630  namespace Serialization {
1630                      assert(false /* unknown floating point type */);                      assert(false /* unknown floating point type */);
1631              } else if (type.isBool()) {              } else if (type.isBool()) {
1632                  _popIntBlob<uint8_t>(p, end, obj.m_data);                  _popIntBlob<uint8_t>(p, end, obj.m_data);
1633                } else if (type.isString()) {
1634                    _popStringBlob(p, end, obj.m_data);
1635              } else {              } else {
1636                  assert(false /* unknown primitive type */);                  assert(false /* unknown primitive type */);
1637              }              }
# Line 2062  namespace Serialization { Line 2172  namespace Serialization {
2172          m_isModified = true;          m_isModified = true;
2173      }      }
2174    
2175        /** @brief Set new textual string for given String object.
2176         *
2177         * Sets the new textual string @a value to the given String @a object.
2178         *
2179         * @param object - the String object to be changed
2180         * @param value - the new textual string to be assigned to the @a object
2181         * @throws Exception if @a object is not a String type.
2182         */
2183        void Archive::setStringValue(Object& object, String value) {
2184            if (!object) return;
2185            if (!object.type().isString())
2186                throw Exception("Not a String data type");
2187            Object* pObject = &object;
2188            if (object.type().isPointer()) {
2189                Object& obj = objectByUID(object.uid(1));
2190                if (!obj) return;
2191                pObject = &obj;
2192            }
2193            pObject->m_data.resize(value.length() + 1);
2194            char* ptr = (char*) &pObject->m_data[0];
2195            strcpy(ptr, &value[0]);
2196            m_isModified = true;
2197        }
2198    
2199      /** @brief Automatically cast and assign appropriate value to object.      /** @brief Automatically cast and assign appropriate value to object.
2200       *       *
2201       * 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 2224  namespace Serialization {
2224                  setBoolValue(object, false);                  setBoolValue(object, false);
2225              else              else
2226                  setBoolValue(object, atof(value.c_str()));                  setBoolValue(object, atof(value.c_str()));
2227          } else if (type.isEnum())          } else if (type.isString())
2228                setStringValue(object, value);
2229            else if (type.isEnum())
2230              setEnumValue(object, atoll(value.c_str()));              setEnumValue(object, atoll(value.c_str()));
2231          else          else
2232              throw Exception("Not a primitive data type");              throw Exception("Not a primitive data type");
# Line 2208  namespace Serialization { Line 2344  namespace Serialization {
2344          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());          memcpy(pDst, &srcObj.rawData()[0], dstObj.type().size());
2345      }      }
2346    
2347        void Archive::Syncer::syncString(const Object& dstObj, const Object& srcObj) {
2348            assert(dstObj.type().isString());
2349            assert(dstObj.type() == srcObj.type());
2350            String* pDst = (String*)(void*)dstObj.uid().id;
2351            *pDst = (String) (const char*) &srcObj.rawData()[0];
2352        }
2353    
2354      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {      void Archive::Syncer::syncPointer(const Object& dstObj, const Object& srcObj) {
2355          assert(dstObj.type().isPointer());          assert(dstObj.type().isPointer());
2356          assert(dstObj.type() == srcObj.type());          assert(dstObj.type() == srcObj.type());
# Line 2234  namespace Serialization { Line 2377  namespace Serialization {
2377          m_dst.m_allObjects.erase(dstObj.uid());          m_dst.m_allObjects.erase(dstObj.uid());
2378    
2379          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {          if (dstObj.type().isPrimitive() && !dstObj.type().isPointer()) {
2380              syncPrimitive(dstObj, srcObj);              if (dstObj.type().isString())
2381                    syncString(dstObj, srcObj);
2382                else
2383                    syncPrimitive(dstObj, srcObj);
2384              return; // end of recursion              return; // end of recursion
2385          }          }
2386    
# Line 2286  namespace Serialization { Line 2432  namespace Serialization {
2432      // *************** Exception ***************      // *************** Exception ***************
2433      // *      // *
2434    
2435        Exception::Exception() {
2436        }
2437    
2438        Exception::Exception(String format, ...) {
2439            va_list arg;
2440            va_start(arg, format);
2441            Message = assemble(format, arg);
2442            va_end(arg);
2443        }
2444    
2445        Exception::Exception(String format, va_list arg) {
2446            Message = assemble(format, arg);
2447        }
2448    
2449      /** @brief Print exception message to stdout.      /** @brief Print exception message to stdout.
2450       *       *
2451       * Prints the message of this Exception to the currently defined standard       * Prints the message of this Exception to the currently defined standard
# Line 2295  namespace Serialization { Line 2455  namespace Serialization {
2455          std::cout << "Serialization::Exception: " << Message << std::endl;          std::cout << "Serialization::Exception: " << Message << std::endl;
2456      }      }
2457    
2458        String Exception::assemble(String format, va_list arg) {
2459            char* buf = NULL;
2460            vasprintf(&buf, format.c_str(), arg);
2461            String s = buf;
2462            free(buf);
2463            return s;
2464        }
2465    
2466  } // namespace Serialization  } // namespace Serialization

Legend:
Removed from v.3185  
changed lines
  Added in v.3771

  ViewVC Help
Powered by ViewVC