1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2015 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stddef.h>
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <limits>
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/logging.h"
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/pickle.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "ipc/ipc_param_traits.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/array_internal.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/native_struct_data.h"
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/serialization_util.h"
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/native_struct.h"
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace internal {
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztemplate <typename MaybeConstUserType>
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct NativeStructSerializerImpl {
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  using UserType = typename std::remove_const<MaybeConstUserType>::type;
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  using Traits = IPC::ParamTraits<UserType>;
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static size_t PrepareToSerialize(MaybeConstUserType& value,
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                   SerializationContext* context) {
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::PickleSizer sizer;
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traits::GetSize(&sizer, value);
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return Align(sizer.payload_size() + sizeof(ArrayHeader));
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static void Serialize(MaybeConstUserType& value,
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        Buffer* buffer,
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        NativeStruct_Data** out,
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        SerializationContext* context) {
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::Pickle pickle;
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traits::Write(&pickle, value);
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if DCHECK_IS_ON()
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::PickleSizer sizer;
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traits::GetSize(&sizer, value);
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(sizer.payload_size(), pickle.payload_size());
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    size_t total_size = pickle.payload_size() + sizeof(ArrayHeader);
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_LT(total_size, std::numeric_limits<uint32_t>::max());
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Allocate a uint8 array, initialize its header, and copy the Pickle in.
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ArrayHeader* header =
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        reinterpret_cast<ArrayHeader*>(buffer->Allocate(total_size));
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    header->num_bytes = static_cast<uint32_t>(total_size);
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    header->num_elements = static_cast<uint32_t>(pickle.payload_size());
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    memcpy(reinterpret_cast<char*>(header) + sizeof(ArrayHeader),
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez           pickle.payload(), pickle.payload_size());
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    *out = reinterpret_cast<NativeStruct_Data*>(header);
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static bool Deserialize(NativeStruct_Data* data,
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          UserType* out,
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          SerializationContext* context) {
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!data)
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return false;
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Construct a temporary base::Pickle view over the array data. Note that
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // the Array_Data is laid out like this:
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //   [num_bytes (4 bytes)] [num_elements (4 bytes)] [elements...]
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // and base::Pickle expects to view data like this:
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //   [payload_size (4 bytes)] [header bytes ...] [payload...]
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Because ArrayHeader's num_bytes includes the length of the header and
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Pickle's payload_size does not, we need to adjust the stored value
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // momentarily so Pickle can view the data.
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data);
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_GE(header->num_bytes, sizeof(ArrayHeader));
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    header->num_bytes -= sizeof(ArrayHeader);
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    {
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // Construct a view over the full Array_Data, including our hacked up
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // header. Pickle will infer from this that the header is 8 bytes long,
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // and the payload will contain all of the pickled bytes.
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::Pickle pickle_view(reinterpret_cast<const char*>(header),
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                               header->num_bytes + sizeof(ArrayHeader));
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::PickleIterator iter(pickle_view);
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (!Traits::Read(&pickle_view, &iter, out))
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return false;
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Return the header to its original state.
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    header->num_bytes += sizeof(ArrayHeader);
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct UnmappedNativeStructSerializerImpl {
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static size_t PrepareToSerialize(const NativeStructPtr& input,
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                   SerializationContext* context);
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static void Serialize(const NativeStructPtr& input,
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        Buffer* buffer,
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        NativeStruct_Data** output,
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        SerializationContext* context);
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static bool Deserialize(NativeStruct_Data* input,
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          NativeStructPtr* output,
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          SerializationContext* context);
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztemplate <>
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct NativeStructSerializerImpl<NativeStructPtr>
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : public UnmappedNativeStructSerializerImpl {};
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztemplate <>
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct NativeStructSerializerImpl<const NativeStructPtr>
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : public UnmappedNativeStructSerializerImpl {};
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztemplate <typename MaybeConstUserType>
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct Serializer<NativeStructPtr, MaybeConstUserType>
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : public NativeStructSerializerImpl<MaybeConstUserType> {};
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace internal
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_SERIALIZATION_H_
133