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