• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PrepareToSerializeNativeStructSerializerImpl33   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 
SerializeNativeStructSerializerImpl40   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 
DeserializeNativeStructSerializerImpl67   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