// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_
#include <string.h>
#include <type_traits>
#include "base/numerics/safe_math.h"
#include "mojo/public/cpp/bindings/array_traits_span.h"
#include "mojo/public/cpp/bindings/array_traits_stl.h"
#include "mojo/public/cpp/bindings/lib/array_serialization.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
#include "mojo/public/cpp/bindings/lib/handle_serialization.h"
#include "mojo/public/cpp/bindings/lib/map_serialization.h"
#include "mojo/public/cpp/bindings/lib/string_serialization.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"
#include "mojo/public/cpp/bindings/map_traits_flat_map.h"
#include "mojo/public/cpp/bindings/map_traits_stl.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/string_traits_stl.h"
#include "mojo/public/cpp/bindings/string_traits_string_piece.h"
namespace mojo {
namespace internal {
template <typename MojomType, typename EnableType = void>
struct MojomSerializationImplTraits;
template <typename MojomType>
struct MojomSerializationImplTraits<
MojomType,
typename std::enable_if<
BelongsTo<MojomType, MojomTypeCategory::STRUCT>::value>::type> {
template <typename MaybeConstUserType, typename WriterType>
static void Serialize(MaybeConstUserType& input,
Buffer* buffer,
WriterType* writer,
SerializationContext* context) {
mojo::internal::Serialize<MojomType>(input, buffer, writer, context);
}
};
template <typename MojomType>
struct MojomSerializationImplTraits<
MojomType,
typename std::enable_if<
BelongsTo<MojomType, MojomTypeCategory::UNION>::value>::type> {
template <typename MaybeConstUserType, typename WriterType>
static void Serialize(MaybeConstUserType& input,
Buffer* buffer,
WriterType* writer,
SerializationContext* context) {
mojo::internal::Serialize<MojomType>(input, buffer, writer,
false /* inline */, context);
}
};
template <typename MojomType, typename UserType>
mojo::Message SerializeAsMessageImpl(UserType* input) {
SerializationContext context;
mojo::Message message(0, 0, 0, 0, nullptr);
typename MojomTypeTraits<MojomType>::Data::BufferWriter writer;
MojomSerializationImplTraits<MojomType>::Serialize(
*input, message.payload_buffer(), &writer, &context);
message.AttachHandlesFromSerializationContext(&context);
return message;
}
template <typename MojomType, typename DataArrayType, typename UserType>
DataArrayType SerializeImpl(UserType* input) {
static_assert(BelongsTo<MojomType, MojomTypeCategory::STRUCT>::value ||
BelongsTo<MojomType, MojomTypeCategory::UNION>::value,
"Unexpected type.");
Message message = SerializeAsMessageImpl<MojomType>(input);
uint32_t size = message.payload_num_bytes();
DataArrayType result(size);
if (size)
memcpy(&result.front(), message.payload(), size);
return result;
}
template <typename MojomType, typename UserType>
bool DeserializeImpl(const void* data,
size_t data_num_bytes,
std::vector<mojo::ScopedHandle> handles,
UserType* output,
bool (*validate_func)(const void*, ValidationContext*)) {
static_assert(BelongsTo<MojomType, MojomTypeCategory::STRUCT>::value ||
BelongsTo<MojomType, MojomTypeCategory::UNION>::value,
"Unexpected type.");
using DataType = typename MojomTypeTraits<MojomType>::Data;
const void* input_buffer = data_num_bytes == 0 ? nullptr : data;
void* aligned_input_buffer = nullptr;
// Validation code will insist that the input buffer is aligned, so we ensure
// that here. If the input data is not aligned, we (sadly) copy into an
// aligned buffer. In practice this should happen only rarely if ever.
bool need_copy = !IsAligned(input_buffer);
if (need_copy) {
aligned_input_buffer = malloc(data_num_bytes);
DCHECK(IsAligned(aligned_input_buffer));
memcpy(aligned_input_buffer, data, data_num_bytes);
input_buffer = aligned_input_buffer;
}
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(data_num_bytes));
ValidationContext validation_context(
input_buffer, static_cast<uint32_t>(data_num_bytes), handles.size(), 0);
bool result = false;
if (validate_func(input_buffer, &validation_context)) {
SerializationContext context;
*context.mutable_handles() = std::move(handles);
result = Deserialize<MojomType>(
reinterpret_cast<DataType*>(const_cast<void*>(input_buffer)), output,
&context);
}
if (aligned_input_buffer)
free(aligned_input_buffer);
return result;
}
} // namespace internal
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_