LCOV - code coverage report
Current view: directory - src/shared/serialization - serialization.h (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 138 115 83.3 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /* -*- c++ -*- */
       2                 : /*
       3                 :  * Copyright (c) 2013 The Native Client Authors. All rights reserved.
       4                 :  * Use of this source code is governed by a BSD-style license that can be
       5                 :  * found in the LICENSE file.
       6                 :  */
       7                 : 
       8                 : #ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
       9                 : #define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
      10                 : 
      11                 : #if defined(__native_client__) || (NACL_LINUX && !NACL_ANDROID)
      12                 : # define NACL_HAS_IEEE_754
      13                 : // Make sure fp is not dead code and is tested.  DO NOT USE the fp
      14                 : // interface until we have a portability version of ieee754.h!
      15                 : #endif
      16                 : 
      17                 : #if defined(NACL_HAS_IEEE_754)
      18                 : # include <ieee754.h>
      19                 : #endif
      20                 : 
      21                 : #include <vector>
      22                 : #include <string>
      23                 : 
      24                 : #include "native_client/src/include/portability.h"
      25                 : #include "native_client/src/include/nacl_compiler_annotations.h"
      26                 : #include "native_client/src/shared/platform/nacl_check.h"
      27                 : 
      28                 : // SerializationBuffer enables serializing basic types and vectors
      29                 : 
      30                 : namespace nacl {
      31                 : 
      32                 : class SerializationBuffer;
      33                 : 
      34                 : template<typename T> class SerializationTraits;
      35                 : 
      36                 : enum {
      37                 :   kIllegalTag = -1,
      38                 : 
      39                 :   kUint8 = 0,
      40                 :   kInt8 = 1,
      41                 :   kUint16 = 2,
      42                 :   kInt16 = 3,
      43                 :   kUint32 = 4,
      44                 :   kInt32 = 5,
      45                 :   kUint64 = 6,
      46                 :   kInt64 = 7,
      47                 : 
      48                 : #if defined(NACL_HAS_IEEE_754)
      49                 :   kFloat = 8,
      50                 :   kDouble = 9,
      51                 :   kLongDouble = 10,
      52                 : #endif
      53                 : 
      54                 :   kCString = 11,
      55                 :   kString = 12,
      56                 : 
      57                 :   kRecursiveVector = 31,
      58                 :   kVectorOffset = 32
      59                 : };
      60                 : 
      61                 : class SerializationBuffer {
      62                 :  public:
      63                 :   SerializationBuffer();
      64                 : 
      65                 :   // This initializes the Serialization buffer from |data_buffer|
      66                 :   // containing |nbytes| of data.  A copy of the data is made rather
      67                 :   // than transferring ownership, which is suboptimal.
      68                 :   SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
      69                 : 
      70                 :   template<typename T> bool Serialize(T basic) NACL_WUR;
      71                 : 
      72                 :   template<typename T> bool Serialize(std::vector<T> const& v) NACL_WUR;
      73                 : 
      74                 :   bool Serialize(char const *cstr) NACL_WUR;
      75                 :   bool Serialize(char const *cstr, size_t char_count) NACL_WUR;
      76                 : 
      77                 :   bool Serialize(std::string str) NACL_WUR;
      78                 : 
      79               1 :   int ReadTag() {
      80               1 :     if (bytes_unread() < kTagBytes) {
      81               0 :       return kIllegalTag;
      82                 :     }
      83               1 :     return buffer_[read_ix_++];
      84               1 :   }
      85                 : 
      86                 :   template<typename T> bool Deserialize(T *basic) NACL_WUR;
      87                 : 
      88                 :   template<typename T> bool Deserialize(std::vector<T> *v) NACL_WUR;
      89                 : 
      90                 :   // This function deserializes into the provided buffer at |cstr|.
      91                 :   // The parameter *buffer_size is an in-out parameter, initially
      92                 :   // containing the available space at |cstr|.  If there are decoding
      93                 :   // errors, this function returns false.  If it returns true, the
      94                 :   // caller should check *buffer_size -- if there were insufficient
      95                 :   // space, the read position is unchanged and *buffer_size is updated
      96                 :   // to reflect the amount of space that is required; otherwise
      97                 :   // *buffer_size is updated to reflect the actual number of bytes
      98                 :   // written to |cstr|.
      99                 :   bool Deserialize(char *cstr, size_t *buffer_size) NACL_WUR;
     100                 :   // caller provides buffer
     101                 : 
     102                 :   // This method deserializes a NUL-terminated C-style string.  The
     103                 :   // caller receives ownnership of the memory allocated via new[] and
     104                 :   // is responsible for delete[]ing it to release the storage.
     105                 :   bool Deserialize(char **cstr_out) NACL_WUR;
     106                 : 
     107                 :   bool Deserialize(std::string *str) NACL_WUR;
     108                 : 
     109               1 :   size_t num_bytes() const {
     110               1 :     return in_use_;
     111               1 :   }
     112                 : 
     113               1 :   uint8_t const *data() const {
     114                 :     // return buffer_.data();  // C++11 only, not available on windows
     115               1 :     return &buffer_[0];
     116               1 :   }
     117                 : 
     118               1 :   void rewind() {
     119               1 :     read_ix_ = 0;
     120               1 :   }
     121                 : 
     122               1 :   void reset() {
     123               1 :     in_use_ = 0;
     124               1 :     buffer_.clear();
     125               1 :     nbytes_ = 0;
     126               1 :     read_ix_ = 0;
     127               1 :   }
     128                 : 
     129                 :   static const size_t kTagBytes = 1;
     130                 : 
     131                 :  protected:
     132                 :   template<typename T> void AddTag();
     133                 : 
     134                 :   template<typename T> bool CheckTag();
     135                 : 
     136                 :   void AddUint8(uint8_t value);
     137                 :   void AddUint16(uint16_t value);
     138                 :   void AddUint32(uint32_t value);
     139                 :   void AddUint64(uint64_t value);
     140                 : #if defined(NACL_HAS_IEEE_754)
     141                 :   void AddFloat(float value);
     142                 :   void AddDouble(double value);
     143                 :   void AddLongDouble(long double value);
     144                 : #endif
     145                 : 
     146                 :   bool GetUint8(uint8_t *val);
     147                 :   bool GetUint16(uint16_t *val);
     148                 :   bool GetUint32(uint32_t *val);
     149                 :   bool GetUint64(uint64_t *val);
     150                 : #if defined(NACL_HAS_IEEE_754)
     151                 :   bool GetFloat(float *value);
     152                 :   bool GetDouble(double *value);
     153                 :   bool GetLongDouble(long double *value);
     154                 : #endif
     155                 : 
     156               8 :   template<typename T> void AddVal(T value) {
     157                 :     int T_must_be_integral_type[static_cast<T>(1)];
     158                 :     UNREFERENCED_PARAMETER(T_must_be_integral_type);
     159               8 :     if (sizeof(T) == 1) {
     160               2 :       AddUint8(static_cast<uint8_t>(value));
     161               6 :     } else if (sizeof(T) == 2) {
     162               2 :       AddUint16(static_cast<uint16_t>(value));
     163               4 :     } else if (sizeof(T) == 4) {
     164               2 :       AddUint32(static_cast<uint32_t>(value));
     165               2 :     } else if (sizeof(T) == 8) {
     166               2 :       AddUint64(static_cast<uint64_t>(value));
     167                 :     }
     168               8 :   }
     169                 : 
     170               8 :   template<typename T> bool GetVal(T *basic) {
     171                 :     int T_must_be_integral_type[static_cast<T>(1)];
     172                 :     UNREFERENCED_PARAMETER(T_must_be_integral_type);
     173               8 :     if (sizeof(T) == 1) {
     174                 :       uint8_t val;
     175               2 :       return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     176               6 :     } else if (sizeof(T) == 2) {
     177                 :       uint16_t val;
     178               2 :       return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     179               4 :     } else if (sizeof(T) == 4) {
     180                 :       uint32_t val;
     181               2 :       return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     182               2 :     } else if (sizeof(T) == 8) {
     183                 :       uint64_t val;
     184               2 :       return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     185                 :     }
     186               0 :     return false;
     187               8 :   }
     188                 : 
     189                 : #if defined(NACL_HAS_IEEE_754)
     190                 :   void AddVal(float value) {
     191                 :     AddFloat(value);
     192                 :   }
     193                 : 
     194                 :   bool GetVal(float *value) {
     195                 :     return GetFloat(value);
     196                 :   }
     197                 : 
     198                 :   void AddVal(double value) {
     199                 :     AddDouble(value);
     200                 :   }
     201                 : 
     202                 :   bool GetVal(double *value) {
     203                 :     return GetDouble(value);
     204                 :   }
     205                 : 
     206                 :   void AddVal(long double value) {
     207                 :     AddLongDouble(value);
     208                 :   }
     209                 : 
     210                 :   bool GetVal(long double *value) {
     211                 :     return GetLongDouble(value);
     212                 :   }
     213                 : #endif
     214                 : 
     215                 :   template<typename T, bool nested_tagging>
     216                 :   bool Serialize(std::vector<T> const& v);
     217                 : 
     218                 :   // Template metaprogramming to determine at compile time, based on
     219                 :   // whether the type T is a container type or not, whether to tag the
     220                 :   // elements with their own type tag, or to just write the elements
     221                 :   // sans type tag.  For vector containers of simple types such as
     222                 :   // int8_t, tagging every byte is excessive overhead.  NB: see the
     223                 :   // definition below of kTag for vectors.
     224                 :   template<typename T, bool nested_tagging> class SerializeHelper {
     225                 :    public:
     226                 :     static bool DoSerialize(SerializationBuffer *buf,
     227               2 :                             std::vector<T> const& v) {
     228               2 :       size_t orig = buf->cur_write_pos();
     229               2 :       size_t num_elt = v.size();
     230               2 :       if (num_elt > ~(uint32_t) 0) {
     231               0 :         return false;
     232                 :       }
     233               2 :       buf->AddTag<std::vector<T> >();
     234               2 :       buf->AddVal(static_cast<uint32_t>(num_elt));
     235                 : 
     236               2 :       for (size_t ix = 0; ix < v.size(); ++ix) {
     237               2 :         if (!buf->Serialize(v[ix])) {
     238               0 :           buf->reset_write_pos(orig);
     239               0 :           return false;
     240                 :         }
     241               2 :       }
     242               2 :       return true;
     243               2 :     }
     244                 :   };
     245                 : 
     246                 :   template<typename T> class SerializeHelper<T, false> {
     247                 :    public:
     248                 :     static bool DoSerialize(SerializationBuffer *buf,
     249               1 :                             std::vector<T> const& v) {
     250               1 :       size_t num_elt = v.size();
     251               1 :       if (num_elt > ~(uint32_t) 0) {
     252               0 :         return false;
     253                 :       }
     254               1 :       buf->AddTag<std::vector<T> >();
     255               1 :       buf->AddVal(static_cast<uint32_t>(num_elt));
     256                 : 
     257               1 :       for (size_t ix = 0; ix < v.size(); ++ix) {
     258               1 :         buf->AddVal(v[ix]);
     259               1 :       }
     260               1 :       return true;
     261               1 :     }
     262                 :   };
     263                 : 
     264                 :   template<typename T, bool b> friend class SerializeHelper;
     265                 : 
     266                 :   template<typename T, bool nested_tagging> class DeserializeHelper {
     267                 :    public:
     268                 :     static bool DoDeserialize(SerializationBuffer *buf,
     269               1 :                               std::vector<T> *v) {
     270               1 :       size_t orig = buf->cur_read_pos();
     271               1 :       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
     272               0 :         buf->reset_read_pos(orig);
     273               0 :         return false;
     274                 :       }
     275                 :       uint32_t num_elt;
     276               1 :       if (!buf->GetVal(&num_elt)) {
     277               0 :         buf->reset_read_pos(orig);
     278               0 :         return false;
     279                 :       }
     280               1 :       for (size_t ix = 0; ix < num_elt; ++ix) {
     281               1 :         T val;
     282               1 :         if (!buf->Deserialize(&val)) {
     283               0 :           buf->reset_read_pos(orig);
     284               0 :           return false;
     285                 :         }
     286               1 :         v->push_back(val);
     287               1 :       }
     288               1 :       return true;
     289               1 :     }
     290                 :   };
     291                 : 
     292                 :   template<typename T> class DeserializeHelper<T, false> {
     293                 :    public:
     294                 :     static bool DoDeserialize(SerializationBuffer *buf,
     295               1 :                               std::vector<T> *v) {
     296               1 :       size_t orig = buf->cur_read_pos();
     297               1 :       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
     298               0 :         buf->reset_read_pos(orig);
     299               0 :         return false;
     300                 :       }
     301                 :       uint32_t num_elt;
     302               1 :       if (!buf->GetVal(&num_elt)) {
     303               0 :         buf->reset_read_pos(orig);
     304               0 :         return false;
     305                 :       }
     306               1 :       for (size_t ix = 0; ix < num_elt; ++ix) {
     307                 :         T val;
     308               1 :         if (!buf->GetVal(&val)) {
     309               0 :           buf->reset_read_pos(orig);
     310               0 :           return false;
     311                 :         }
     312               1 :         v->push_back(val);
     313               1 :       }
     314               1 :       return true;
     315               1 :     }
     316                 :   };
     317                 : 
     318                 :   template<typename T, bool b> friend class DeserializeHelper;
     319                 : 
     320                 :   // TODO(bsy): consider doing something along the lines of
     321                 :   //
     322                 :   // template<typename T> Serialize(T stl_container) {
     323                 :   //   AddTag<T>();  // how?
     324                 :   //   for (T::const_iterator it = stl_container.begin();
     325                 :   //        it != stl_container.end();
     326                 :   //        ++it) {
     327                 :   //     Serialize(*it);
     328                 :   //     // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
     329                 :   //     // is false.
     330                 :   //   }
     331                 :   // }
     332                 :   //
     333                 :   // This means that the container type would probably be omitted or a
     334                 :   // generic stl_container type tag would be used -- or we'd have to
     335                 :   // enumerate all container types.
     336                 : 
     337                 :  private:
     338                 :   std::vector<uint8_t> buffer_;
     339                 :   size_t nbytes_;
     340                 :   size_t in_use_;
     341                 :   size_t read_ix_;
     342                 : 
     343                 :   void EnsureTotalSize(size_t req_size);
     344                 :   void EnsureAvailableSpace(size_t req_space);
     345                 : 
     346               1 :   size_t bytes_unread() const {
     347               1 :     return in_use_ - read_ix_;
     348               1 :   }
     349                 : 
     350               1 :   size_t cur_read_pos() const {
     351               1 :     return read_ix_;
     352               1 :   }
     353                 : 
     354               1 :   void reset_read_pos(size_t pos) {
     355               1 :     read_ix_ = pos;
     356               1 :   }
     357                 : 
     358               1 :   size_t cur_write_pos() const {
     359               1 :     return in_use_;
     360               1 :   }
     361                 : 
     362               0 :   void reset_write_pos(size_t pos) {
     363               0 :     in_use_ = pos;
     364               0 :   }
     365                 : };
     366                 : 
     367              13 : template<typename T> void SerializationBuffer::AddTag() {
     368              13 :   AddUint8(SerializationTraits<T>::kTag);
     369              13 : }
     370                 : 
     371               8 : template<typename T> bool SerializationBuffer::Serialize(T basic) {
     372               8 :   AddTag<T>();
     373               8 :   AddVal(basic);
     374               8 :   return true;
     375               8 : }
     376                 : 
     377                 : template<typename T> bool SerializationBuffer::Serialize(
     378               3 :     std::vector<T> const& v) {
     379                 :   return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
     380               3 :       DoSerialize(this, v);
     381               3 : }
     382                 : 
     383               8 : template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
     384               8 :   size_t orig = cur_read_pos();
     385               8 :   if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
     386               1 :     return false;
     387                 :   }
     388                 :   uint8_t tag;
     389               8 :   if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
     390               0 :     reset_read_pos(orig);
     391               0 :     return false;
     392                 :   }
     393                 :   // if BytesAvail >= tag + serialization_size
     394               8 :   (void) GetVal(basic);
     395               8 :   return true;
     396               8 : }
     397                 : 
     398                 : template<typename T> bool SerializationBuffer::Deserialize(
     399               2 :     std::vector<T> *v) {
     400                 :   return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
     401               2 :       DoDeserialize(this, v);
     402               2 : }
     403                 : 
     404                 : template<> class SerializationTraits<uint8_t> {
     405                 :  public:
     406                 :   static const int kTag = kUint8;
     407                 :   static const int kBytes = 1;
     408                 :   static const bool kNestedTag = false;
     409                 : };
     410                 : 
     411                 : template<> class SerializationTraits<int8_t> {
     412                 :  public:
     413                 :   static const int kTag = kInt8;
     414                 :   static const int kBytes = 1;
     415                 :   static const bool kNestedTag = false;
     416                 : };
     417                 : 
     418                 : template<> class SerializationTraits<uint16_t> {
     419                 :  public:
     420                 :   static const int kTag = kUint16;
     421                 :   static const int kBytes = 2;
     422                 :   static const bool kNestedTag = false;
     423                 : };
     424                 : 
     425                 : template<> class SerializationTraits<int16_t> {
     426                 :  public:
     427                 :   static const int kTag = kInt16;
     428                 :   static const int kBytes = 2;
     429                 :   static const bool kNestedTag = false;
     430                 : };
     431                 : 
     432                 : template<> class SerializationTraits<uint32_t> {
     433                 :  public:
     434                 :   static const int kTag = kUint32;
     435                 :   static const int kBytes = 4;
     436                 :   static const bool kNestedTag = false;
     437                 : };
     438                 : 
     439                 : template<> class SerializationTraits<int32_t> {
     440                 :  public:
     441                 :   static const int kTag = kInt32;
     442                 :   static const int kBytes = 4;
     443                 :   static const bool kNestedTag = false;
     444                 : };
     445                 : 
     446                 : template<> class SerializationTraits<uint64_t> {
     447                 :  public:
     448                 :   static const int kTag = kUint64;
     449                 :   static const int kBytes = 8;
     450                 :   static const bool kNestedTag = false;
     451                 : };
     452                 : 
     453                 : template<> class SerializationTraits<int64_t> {
     454                 :  public:
     455                 :   static const int kTag = kInt64;
     456                 :   static const int kBytes = 8;
     457                 :   static const bool kNestedTag = false;
     458                 : };
     459                 : 
     460                 : #if defined(NACL_HAS_IEEE_754)
     461                 : template<> class SerializationTraits<float> {
     462                 :  public:
     463                 :   static const int kTag = kFloat;
     464                 :   static const int kBytes = 4;
     465                 :   static const bool kNestedTag = false;
     466                 : };
     467                 : 
     468                 : template<> class SerializationTraits<double> {
     469                 :  public:
     470                 :   static const int kTag = kDouble;
     471                 :   static const int kBytes = 8;
     472                 :   static const bool kNestedTag = false;
     473                 : };
     474                 : 
     475                 : template<> class SerializationTraits<long double> {
     476                 :  public:
     477                 :   static const int kTag = kLongDouble;
     478                 :   static const int kBytes = 10;
     479                 :   static const bool kNestedTag = false;
     480                 : };
     481                 : #endif
     482                 : 
     483                 : template<> class SerializationTraits<char *> {
     484                 :  public:
     485                 :   static const int kTag = kCString;
     486                 :   static const bool kNestedTag = true;
     487                 : };
     488                 : 
     489                 : template<> class SerializationTraits<std::string> {
     490                 :  public:
     491                 :   static const int kTag = kString;
     492                 :   static const bool kNestedTag = true;
     493                 : };
     494                 : 
     495                 : // We want the type tag for vector<T>, when the type T is a basic
     496                 : // type, to incorporate the type tag for T.  This way, we do not tag
     497                 : // each vector element (see SerializeHelper etc above), and yet the
     498                 : // type information is present.  When T is not a basic type (e.g., it
     499                 : // is a string, a vector<U>, or some other container to be added), we
     500                 : // don't want to just add the kVectorOffset to the type tag for T,
     501                 : // since deep nesting of containers could cause the tag to overflow.
     502                 : // Assuming that the type T nested containers are not empty, paying
     503                 : // the cost of tagging each element of the vector is not a huge
     504                 : // overhead.
     505                 : template<typename T> class SerializationTraits<std::vector<T> > {
     506                 :  private:
     507                 :   template<typename S, bool b> class RecursiveOrNotTag {
     508                 :    public:
     509                 :     static const int kVectorTag = kRecursiveVector;
     510                 :   };
     511                 :   template<typename S> class RecursiveOrNotTag<S, false> {
     512                 :    public:
     513                 :     static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
     514                 :   };
     515                 :  public:
     516                 :   static const int kTag =
     517                 :       RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
     518                 :   static const bool kNestedTag = true;
     519                 : };
     520                 : 
     521                 : }  // namespace nacl
     522                 : 
     523                 : #endif

Generated by: LCOV version 1.7