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