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