Wisp 1.3.1 C++ Unit Test Coverage
Current view: top level - ssrc/wisp - serialization.h (source / functions) Hit Total Coverage
Test: Wisp 1.3.1 C++ Unit Tests Lines: 66 67 98.5 %
Date: 2017-01-16 Functions: 39 40 97.5 %
Branches: 101 200 50.5 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright 2006-2008 Savarese Software Research Corporation
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at
       6                 :            :  *
       7                 :            :  *     http://www.savarese.com/software/ApacheLicense-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : /**
      17                 :            :  * @file
      18                 :            :  * This header defines serialization support classes and functions.
      19                 :            :  */
      20                 :            : 
      21                 :            : #ifndef __SSRC_WISP_SERIALIZATION_H
      22                 :            : #define __SSRC_WISP_SERIALIZATION_H
      23                 :            : 
      24                 :            : #include <ssrc/wisp-packages.h>
      25                 :            : #include <ssrc/spread/detail/ByteBuffer.h>
      26                 :            : 
      27                 :            : #include <utility>
      28                 :            : 
      29                 :            : #include <boost/iostreams/stream.hpp>
      30                 :            : #include <boost/iostreams/device/array.hpp>
      31                 :            : 
      32                 :            : #include <boost/archive/binary_iarchive.hpp>
      33                 :            : #include <boost/archive/binary_oarchive.hpp>
      34                 :            : 
      35                 :            : #include <boost/serialization/split_free.hpp>
      36                 :            : #include <boost/serialization/binary_object.hpp>
      37                 :            : 
      38                 :            : /**
      39                 :            :  * Opens the boost::serialization namespace so you can add custom serialize
      40                 :            :  * functions.  Close the serialize function definition block with
      41                 :            :  * __END_BOOST_SERIALIZATION.
      42                 :            :  */
      43                 :            : #define __BEGIN_BOOST_SERIALIZATION \
      44                 :            : namespace boost { \
      45                 :            :   namespace serialization { 
      46                 :            : 
      47                 :            : /**
      48                 :            :  * Closes the boost::serialization namespace started with
      49                 :            :  * __BEGIN_BOOST_SERIALIZATION.
      50                 :            :  */
      51                 :            : #define __END_BOOST_SERIALIZATION \
      52                 :            :   } \
      53                 :            : }
      54                 :            : 
      55                 :            : __BEGIN_NS_SSRC_WISP
      56                 :            : 
      57                 :            : using NS_SSRC_SPREAD::detail::ByteBuffer;
      58                 :            : 
      59                 :            : namespace detail {
      60                 :            :   /**
      61                 :            :    * This is a Boost iostreams direct device whose begin and end
      62                 :            :    * pointers can be modified.  Unfortunately, Boost iostreams stream
      63                 :            :    * buffers make their own copies of the pointers.  Therefore, even
      64                 :            :    * after resetting the device pointers, you have to reopen the
      65                 :            :    * stream buffer.
      66                 :            :    */
      67                 :            :   template<typename Ch, typename mode_type = boost::iostreams::seekable>
      68                 :            :   class array_device_adapter {
      69                 :            :   public:
      70                 :            :     typedef Ch char_type;
      71                 :            :     typedef std::pair<char_type*, char_type*>  pair_type;
      72                 :            : 
      73                 :        438 :     struct category :
      74                 :            :       public mode_type,
      75                 :            :       public boost::iostreams::device_tag,
      76                 :            :       public boost::iostreams::direct_tag
      77                 :            :     { };
      78                 :            : 
      79                 :            :   private:
      80                 :            :     char_type *_begin, *_end;
      81                 :            : 
      82                 :            :   public:
      83                 :            : 
      84                 :         26 :     array_device_adapter() : _begin(0), _end(0) { }
      85                 :            : 
      86                 :            :     array_device_adapter(char_type* begin, char_type* end) :
      87                 :            :       _begin(begin), _end(end)
      88                 :            :     { }
      89                 :            : 
      90                 :            :     array_device_adapter(char_type* begin, std::size_t size) :
      91                 :            :       _begin(begin), _end(begin + size)
      92                 :            :     { }
      93                 :            : 
      94                 :            :     void init(char_type* begin, char_type* end) {
      95                 :            :       _begin = begin;
      96                 :            :       _end   = end;
      97                 :            :     }
      98                 :            : 
      99                 :        219 :     void init(char_type* begin, std::size_t size) {
     100                 :        219 :       _begin = begin;
     101                 :        219 :       _end   = begin + size;
     102                 :        219 :     }
     103                 :            : 
     104                 :            :     void set_size(std::size_t size) {
     105                 :            :       _end = _begin + size;
     106                 :            :     }
     107                 :            : 
     108                 :        219 :     pair_type input_sequence() {
     109                 :        219 :       return pair_type(_begin, _end);
     110                 :            :     }
     111                 :            : 
     112                 :        219 :     pair_type output_sequence() {
     113                 :        219 :       return pair_type(_begin, _end);
     114                 :            :     }
     115                 :            :   };
     116                 :            : 
     117                 :            :   typedef array_device_adapter<char> char_array_source;
     118                 :            :   typedef array_device_adapter<char> char_array_sink;
     119                 :            : 
     120                 :            :   // This class is an unfortunately required workaround for a change
     121                 :            :   // and possible bug in Boost 1.42.0 which causes stream_buffer::open to
     122                 :            :   // throw an "already open" exception even if the buffer has been closed.
     123                 :            :   template<typename DeviceAdapter>
     124                 :         52 :   struct char_array_streambuf :
     125                 :            :     public boost::iostreams::stream_buffer<DeviceAdapter>
     126                 :            :   {
     127                 :            :     typedef boost::iostreams::stream_buffer<DeviceAdapter> super;
     128                 :            :     typedef
     129                 :            :     boost::iostreams::detail::direct_streambuf<DeviceAdapter,
     130                 :            :                                                typename super::traits_type>
     131                 :            :     direct_streambuf;
     132                 :            : 
     133                 :        219 :     void open(const DeviceAdapter & device_adapter) {
     134                 :        219 :       direct_streambuf::open(device_adapter, 0, 0);
     135                 :        219 :     }
     136                 :            :   };
     137                 :            : 
     138                 :            :   typedef char_array_streambuf<char_array_source> char_array_source_buffer;
     139                 :            :   typedef char_array_streambuf<char_array_sink> char_array_sink_buffer;
     140                 :            : }
     141                 :            : 
     142                 :            : /**
     143                 :            :  * Packer serializes objects into ssrc::spread::detail::ByteBuffer instances
     144                 :            :  * (usually a ssrc::spread::Message instance).  Each object type must have
     145                 :            :  * a Boost serialize function or method defined (or load and save).
     146                 :            :  *
     147                 :            :  * @param Archive The archive type to use for serialization.
     148                 :            :  */
     149                 :            : template<typename Archive>
     150                 :         26 : class Packer {
     151                 :            : public:
     152                 :            :   typedef detail::char_array_sink sink_type; 
     153                 :            :   typedef detail::char_array_sink_buffer sink_buffer;
     154                 :            :   typedef Archive output_archive;
     155                 :            : 
     156                 :            : protected:
     157                 :            :   sink_type _sink;
     158                 :            :   sink_buffer _out_buf;
     159                 :            : 
     160                 :            : public:
     161                 :            : 
     162                 :            :   /**
     163                 :            :    * Serializes an object into a buffer.  The type of the object is
     164                 :            :    * automatically inferred by the compiler.  The object write starts
     165                 :            :    * at the current buffer offset.  After the object is serialized,
     166                 :            :    * the buffer size is adjusted and its write offset advanced to the
     167                 :            :    * end of the buffer.  The buffer must have enough room to hold the
     168                 :            :    * data written or an exception will be thrown (std::ios_base::failure).
     169                 :            :    *
     170                 :            :    * @param obj The object to serialize.
     171                 :            :    * @param buffer The buffer that will store the object.
     172                 :            :    * @param archive_flags Boost archive constructor flags.
     173                 :            :    * @return The number of bytes written.
     174                 :            :    * @throw boost::archive::archive_exception If there is an archive
     175                 :            :    *        writing error.
     176                 :            :    * @throw std::ios_base::failure If the stream buffer fails, most
     177                 :            :    *        likely because the buffer doesn't have enough room to hold the
     178                 :            :    *        data.
     179                 :            :    */
     180                 :            :   template<typename T>
     181                 :        133 :   unsigned int pack(const T & obj, ByteBuffer & buffer,
     182                 :            :                     const unsigned int archive_flags =
     183                 :            :                     boost::archive::no_header | boost::archive::no_codecvt |
     184                 :            :                     boost::archive::no_tracking)
     185                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     186                 :            :   {
     187                 :            :     unsigned int offset, bytes_written;
     188                 :            : 
     189                 :        133 :     _sink.init(&buffer[0], buffer.capacity());
     190   [ +  -  +  -  :        133 :     _out_buf.open(_sink);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     191   [ +  -  +  -  :        133 :     _out_buf.pubseekoff(buffer.offset(), std::basic_ios<sink_buffer>::beg);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     192                 :            : 
     193   [ +  -  +  -  :        266 :     output_archive out_ar(_out_buf, archive_flags);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     194   [ +  -  +  -  :        133 :     out_ar << obj;
          +  -  +  -  +  
             -  +  +  +  
                      - ]
     195                 :            : 
     196   [ +  -  +  -  :        106 :     offset = _out_buf.pubseekoff(0, std::basic_ios<sink_buffer>::cur);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     197                 :        106 :     bytes_written = offset - buffer.offset();
     198   [ +  -  +  -  :        106 :     buffer.resize(offset);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     199   [ +  -  +  -  :        106 :     buffer.seek(offset);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     200                 :            : 
     201                 :        212 :     return bytes_written;
     202                 :            :   }
     203                 :            : };
     204                 :            : 
     205                 :            : /**
     206                 :            :  * Unpacker deserializes objects from ssrc::spread::detail::ByteBuffer
     207                 :            :  * instances (usually a ssrc::spread::Message instance).  Each object
     208                 :            :  * type must have a Boost serialize function or method defined (or load
     209                 :            :  * and save).
     210                 :            :  *
     211                 :            :  * @param Archive The archive type to use for serialization.
     212                 :            :  */
     213                 :            : template<typename Archive>
     214                 :         26 : class Unpacker {
     215                 :            : public:
     216                 :            :   typedef detail::char_array_source source_type; 
     217                 :            :   typedef detail::char_array_sink_buffer source_buffer;
     218                 :            :   typedef Archive input_archive;
     219                 :            : 
     220                 :            : protected:
     221                 :            :   source_type _source;
     222                 :            :   source_buffer _in_buf;
     223                 :            : 
     224                 :            : public:
     225                 :            : 
     226                 :            :   /**
     227                 :            :    * Deserializes an object from a buffer.  The type of the object is
     228                 :            :    * automatically inferred by the compiler.  The object read starts
     229                 :            :    * at the current buffer offset.  After the object is deserialized,
     230                 :            :    * the buffer offset is adjusted and its read offset advanced to the
     231                 :            :    * end of the data read.
     232                 :            :    *
     233                 :            :    * @param obj The deserialization target.
     234                 :            :    * @param buffer The buffer storing the serialized object.
     235                 :            :    * @param archive_flags Boost archive constructor flags.
     236                 :            :    * @return The number of bytes read.
     237                 :            :    * @throw boost::archive::archive_exception If there is an archive
     238                 :            :    *        read error.
     239                 :            :    * @throw std::ios_base::failure If the stream buffer fails.
     240                 :            :    */
     241                 :            :   template<typename T>
     242                 :         84 :   unsigned int unpack(T & obj, ByteBuffer & buffer,
     243                 :            :                       const unsigned int archive_flags =
     244                 :            :                       boost::archive::no_header | boost::archive::no_codecvt |
     245                 :            :                       boost::archive::no_tracking)
     246                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     247                 :            :   {
     248                 :         84 :     unsigned int bytes_read(0);
     249                 :            : 
     250   [ +  -  +  -  :         84 :     if(buffer.size() > 0) {
             +  -  +  - ]
     251                 :            :       unsigned int offset;
     252                 :            : 
     253                 :         84 :       _source.init(&buffer[0], buffer.size());
     254   [ +  -  +  -  :         84 :       _in_buf.open(_source);
             +  -  +  - ]
     255   [ +  -  +  -  :         84 :       _in_buf.pubseekoff(buffer.offset(), std::basic_ios<source_buffer>::beg);
             +  -  +  - ]
     256                 :            : 
     257   [ +  -  +  -  :        168 :       input_archive in_ar(_in_buf, archive_flags);
             +  -  +  - ]
     258   [ +  -  +  -  :         84 :       in_ar >> obj;
             +  -  +  - ]
     259                 :            : 
     260   [ +  -  +  -  :         84 :       offset = _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::cur);
             +  -  +  - ]
     261                 :         84 :       bytes_read = offset - buffer.offset();
     262   [ +  -  +  -  :         84 :       buffer.seek(offset);
             +  -  +  - ]
     263                 :            :     }
     264                 :            : 
     265                 :         84 :     return bytes_read;
     266                 :            :   }
     267                 :            : 
     268                 :            : 
     269                 :            :   /**
     270                 :            :    * Deserializes an object from a void * buffer.  The type of the object is
     271                 :            :    * automatically inferred by the compiler.  We use this method primarily
     272                 :            :    * to unpack serialized objects from blobs without copying the buffer first.
     273                 :            :    *
     274                 :            :    * @param obj The deserialization target.
     275                 :            :    * @param buffer The buffer storing the serialized object.
     276                 :            :    * @param size The number of bytes in the buffer.
     277                 :            :    * @param archive_flags Boost archive constructor flags.
     278                 :            :    * @return The number of bytes read.
     279                 :            :    * @throw boost::archive::archive_exception If there is an archive
     280                 :            :    *        read error.
     281                 :            :    * @throw std::ios_base::failure If the stream buffer fails.
     282                 :            :    */
     283                 :            :   template<typename T>
     284                 :          2 :   unsigned int unpack(T & obj, const void *buffer, unsigned int size,
     285                 :            :                       const unsigned int archive_flags =
     286                 :            :                       boost::archive::no_header | boost::archive::no_codecvt |
     287                 :            :                       boost::archive::no_tracking)
     288                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     289                 :            :   {
     290                 :          2 :     unsigned int bytes_read(0);
     291                 :            : 
     292   [ +  -  +  - ]:          2 :     if(size > 0) {
     293                 :          2 :       _source.init(static_cast<typename detail::char_array_source::char_type *>(const_cast<void *>(buffer)), size);
     294   [ +  -  +  - ]:          2 :       _in_buf.open(_source);
     295   [ +  -  +  - ]:          2 :       _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::beg);
     296                 :            : 
     297   [ +  -  +  - ]:          4 :       input_archive in_ar(_in_buf, archive_flags);
     298   [ +  -  +  - ]:          2 :       in_ar >> obj;
     299                 :            : 
     300   [ +  -  +  - ]:          2 :       bytes_read = _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::cur);
     301                 :            :     }
     302                 :            : 
     303                 :          2 :     return bytes_read;
     304                 :            :   }
     305                 :            : };
     306                 :            : 
     307                 :            : template<typename P, typename U>
     308                 :            : struct PackingTraits {
     309                 :            :   typedef P packer_type;
     310                 :            :   typedef U unpacker_type;
     311                 :            : };
     312                 :            : 
     313                 :            : typedef Packer<boost::archive::binary_oarchive> BinaryPacker;
     314                 :            : typedef Unpacker<boost::archive::binary_iarchive> BinaryUnpacker;
     315                 :            : typedef PackingTraits<BinaryPacker, BinaryUnpacker> BinaryPackingTraits;
     316                 :            : 
     317                 :            : __END_NS_SSRC_WISP
     318                 :            : 
     319                 :            : __BEGIN_BOOST_SERIALIZATION
     320                 :            : 
     321                 :            : template<class Archive>
     322                 :            : inline
     323                 :            : void save_construct_data(Archive & ar,
     324                 :            :                          const NS_SSRC_SPREAD::detail::ByteBuffer *buffer,
     325                 :            :                          const unsigned int)
     326                 :            : {
     327                 :            :   // Could use capacity, but lets keep it as small as we can.
     328                 :            :   ar << buffer->size();
     329                 :            : }
     330                 :            : 
     331                 :            : template<class Archive>
     332                 :            : inline
     333                 :            : void load_construct_data(Archive & ar,
     334                 :            :                          NS_SSRC_SPREAD::detail::ByteBuffer *buffer,
     335                 :            :                          const unsigned int)
     336                 :            : {
     337                 :            :   unsigned int capacity;
     338                 :            : 
     339                 :            :   ar >> capacity;
     340                 :            :   ::new(buffer)NS_SSRC_SPREAD::detail::ByteBuffer(capacity);
     341                 :            : }
     342                 :            : 
     343                 :            : template<class Archive>
     344                 :         30 : inline void save(Archive & ar,
     345                 :            :                  const NS_SSRC_SPREAD::detail::ByteBuffer & buffer,
     346                 :            :                  const unsigned int)
     347                 :            : {
     348                 :         30 :   unsigned int size = buffer.size();
     349                 :            : 
     350         [ +  - ]:         30 :   ar & size;
     351                 :            : 
     352         [ +  - ]:         30 :   if(size > 0) {
     353                 :         30 :     const binary_object obj(&buffer[0], size);
     354                 :         30 :     unsigned int offset = buffer.offset();
     355   [ +  -  +  + ]:         30 :     ar & offset & obj;
     356                 :            :   }
     357                 :          3 : }
     358                 :            : 
     359                 :            : template<class Archive>
     360                 :          2 : inline void load(Archive & ar,
     361                 :            :                  NS_SSRC_SPREAD::detail::ByteBuffer & buffer,
     362                 :            :                  const unsigned int)
     363                 :            : {
     364                 :            :   unsigned int size;
     365                 :            : 
     366         [ +  - ]:          2 :   ar & size;
     367                 :            : 
     368         [ +  - ]:          2 :   buffer.resize(size);
     369                 :            : 
     370         [ +  - ]:          2 :   if(size > 0) {
     371                 :          2 :     binary_object obj(&buffer[0], size);
     372                 :            :     unsigned int offset;
     373   [ +  -  +  - ]:          2 :     ar & offset & obj;
     374         [ +  - ]:          2 :     buffer.seek(offset);
     375                 :            :   } else
     376         [ #  # ]:          0 :     buffer.rewind();
     377                 :          2 : }
     378                 :            : 
     379                 :            : __END_BOOST_SERIALIZATION
     380                 :            : 
     381                 :         32 : BOOST_SERIALIZATION_SPLIT_FREE(NS_SSRC_SPREAD::detail::ByteBuffer)
     382                 :            : 
     383                 :            : #endif