Home | History | Annotate | Download | only in lib
      1 // Copyright 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <limits>
     12 
     13 #include "base/logging.h"
     14 #include "base/pickle.h"
     15 #include "ipc/ipc_param_traits.h"
     16 #include "mojo/public/cpp/bindings/bindings_export.h"
     17 #include "mojo/public/cpp/bindings/lib/array_internal.h"
     18 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
     19 #include "mojo/public/cpp/bindings/lib/native_struct_data.h"
     20 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
     21 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
     22 #include "mojo/public/cpp/bindings/native_struct.h"
     23 #include "mojo/public/cpp/bindings/native_struct_data_view.h"
     24 
     25 namespace mojo {
     26 namespace internal {
     27 
     28 template <typename MaybeConstUserType>
     29 struct NativeStructSerializerImpl {
     30   using UserType = typename std::remove_const<MaybeConstUserType>::type;
     31   using Traits = IPC::ParamTraits<UserType>;
     32 
     33   static size_t PrepareToSerialize(MaybeConstUserType& value,
     34                                    SerializationContext* context) {
     35     base::PickleSizer sizer;
     36     Traits::GetSize(&sizer, value);
     37     return Align(sizer.payload_size() + sizeof(ArrayHeader));
     38   }
     39 
     40   static void Serialize(MaybeConstUserType& value,
     41                         Buffer* buffer,
     42                         NativeStruct_Data** out,
     43                         SerializationContext* context) {
     44     base::Pickle pickle;
     45     Traits::Write(&pickle, value);
     46 
     47 #if DCHECK_IS_ON()
     48     base::PickleSizer sizer;
     49     Traits::GetSize(&sizer, value);
     50     DCHECK_EQ(sizer.payload_size(), pickle.payload_size());
     51 #endif
     52 
     53     size_t total_size = pickle.payload_size() + sizeof(ArrayHeader);
     54     DCHECK_LT(total_size, std::numeric_limits<uint32_t>::max());
     55 
     56     // Allocate a uint8 array, initialize its header, and copy the Pickle in.
     57     ArrayHeader* header =
     58         reinterpret_cast<ArrayHeader*>(buffer->Allocate(total_size));
     59     header->num_bytes = static_cast<uint32_t>(total_size);
     60     header->num_elements = static_cast<uint32_t>(pickle.payload_size());
     61     memcpy(reinterpret_cast<char*>(header) + sizeof(ArrayHeader),
     62            pickle.payload(), pickle.payload_size());
     63 
     64     *out = reinterpret_cast<NativeStruct_Data*>(header);
     65   }
     66 
     67   static bool Deserialize(NativeStruct_Data* data,
     68                           UserType* out,
     69                           SerializationContext* context) {
     70     if (!data)
     71       return false;
     72 
     73     // Construct a temporary base::Pickle view over the array data. Note that
     74     // the Array_Data is laid out like this:
     75     //
     76     //   [num_bytes (4 bytes)] [num_elements (4 bytes)] [elements...]
     77     //
     78     // and base::Pickle expects to view data like this:
     79     //
     80     //   [payload_size (4 bytes)] [header bytes ...] [payload...]
     81     //
     82     // Because ArrayHeader's num_bytes includes the length of the header and
     83     // Pickle's payload_size does not, we need to adjust the stored value
     84     // momentarily so Pickle can view the data.
     85     ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data);
     86     DCHECK_GE(header->num_bytes, sizeof(ArrayHeader));
     87     header->num_bytes -= sizeof(ArrayHeader);
     88 
     89     {
     90       // Construct a view over the full Array_Data, including our hacked up
     91       // header. Pickle will infer from this that the header is 8 bytes long,
     92       // and the payload will contain all of the pickled bytes.
     93       base::Pickle pickle_view(reinterpret_cast<const char*>(header),
     94                                header->num_bytes + sizeof(ArrayHeader));
     95       base::PickleIterator iter(pickle_view);
     96       if (!Traits::Read(&pickle_view, &iter, out))
     97         return false;
     98     }
     99 
    100     // Return the header to its original state.
    101     header->num_bytes += sizeof(ArrayHeader);
    102 
    103     return true;
    104   }
    105 };
    106 
    107 struct MOJO_CPP_BINDINGS_EXPORT UnmappedNativeStructSerializerImpl {
    108   static size_t PrepareToSerialize(const NativeStructPtr& input,
    109                                    SerializationContext* context);
    110   static void Serialize(const NativeStructPtr& input,
    111                         Buffer* buffer,
    112                         NativeStruct_Data** output,
    113                         SerializationContext* context);
    114   static bool Deserialize(NativeStruct_Data* input,
    115                           NativeStructPtr* output,
    116                           SerializationContext* context);
    117 };
    118 
    119 template <>
    120 struct NativeStructSerializerImpl<NativeStructPtr>
    121     : public UnmappedNativeStructSerializerImpl {};
    122 
    123 template <>
    124 struct NativeStructSerializerImpl<const NativeStructPtr>
    125     : public UnmappedNativeStructSerializerImpl {};
    126 
    127 template <typename MaybeConstUserType>
    128 struct Serializer<NativeStructDataView, MaybeConstUserType>
    129     : public NativeStructSerializerImpl<MaybeConstUserType> {};
    130 
    131 }  // namespace internal
    132 }  // namespace mojo
    133 
    134 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
    135