// Copyright 2013 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_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ #define MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ #include <string.h> #include <vector> #include "mojo/public/bindings/lib/bindings.h" #include "mojo/public/bindings/lib/message.h" namespace mojo { namespace internal { size_t Align(size_t size); // Pointers are encoded as relative offsets. The offsets are relative to the // address of where the offset value is stored, such that the pointer may be // recovered with the expression: // // ptr = reinterpret_cast<char*>(offset) + *offset // // A null pointer is encoded as an offset value of 0. // void EncodePointer(const void* ptr, uint64_t* offset); const void* DecodePointerRaw(const uint64_t* offset); template <typename T> inline void DecodePointer(const uint64_t* offset, T** ptr) { *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); } // Check that the given pointer references memory contained within the message. bool ValidatePointer(const void* ptr, const Message& message); // Handles are encoded as indices into a vector of handles. These functions // manipulate the value of |handle|, mapping it to and from an index. void EncodeHandle(Handle* handle, std::vector<Handle>* handles); bool DecodeHandle(Handle* handle, std::vector<Handle>* handles); // All objects (structs and arrays) support the following operations: // - computing size // - cloning // - encoding pointers and handles // - decoding pointers and handles // // The following functions are used to select the proper ObjectTraits<> // specialization. template <typename T> inline size_t ComputeSizeOf(const T* obj) { return obj ? ObjectTraits<T>::ComputeSizeOf(obj) : 0; } template <typename T> inline T* Clone(const T* obj, Buffer* buf) { return obj ? ObjectTraits<T>::Clone(obj, buf) : NULL; } template <typename T> inline void CloseHandles(T* obj) { if (obj) ObjectTraits<T>::CloseHandles(obj); } template <typename T> inline void EncodePointersAndHandles(T* obj, std::vector<Handle>* handles) { ObjectTraits<T>::EncodePointersAndHandles(obj, handles); } template <typename T> inline bool DecodePointersAndHandles(T* obj, Message* message) { return ObjectTraits<T>::DecodePointersAndHandles(obj, message); } // The following 2 functions are used to encode/decode all objects (structs and // arrays) in a consistent manner. template <typename T> inline void Encode(T* obj, std::vector<Handle>* handles) { if (obj->ptr) EncodePointersAndHandles(obj->ptr, handles); EncodePointer(obj->ptr, &obj->offset); } template <typename T> inline bool Decode(T* obj, Message* message) { DecodePointer(&obj->offset, &obj->ptr); if (obj->ptr) { if (!ValidatePointer(obj->ptr, *message)) return false; if (!DecodePointersAndHandles(obj->ptr, message)) return false; } return true; } // What follows is code to support the ObjectTraits<> specialization of // Array_Data<T>. There are two interesting cases: arrays of primitives and // arrays of objects. Arrays of objects are represented as arrays of pointers // to objects. template <typename T> struct ArrayHelper { typedef T ElementType; static size_t ComputeSizeOfElements(const ArrayHeader* header, const ElementType* elements) { return 0; } static void CloneElements(const ArrayHeader* header, ElementType* elements, Buffer* buf) { } static void EncodePointersAndHandles(const ArrayHeader* header, ElementType* elements, std::vector<Handle>* handles) { } static bool DecodePointersAndHandles(const ArrayHeader* header, ElementType* elements, Message* message) { return true; } }; template <> struct ArrayHelper<Handle> { typedef Handle ElementType; static size_t ComputeSizeOfElements(const ArrayHeader* header, const ElementType* elements) { return 0; } static void CloneElements(const ArrayHeader* header, ElementType* elements, Buffer* buf) { } static void EncodePointersAndHandles(const ArrayHeader* header, ElementType* elements, std::vector<Handle>* handles); static bool DecodePointersAndHandles(const ArrayHeader* header, ElementType* elements, Message* message); }; template <typename P> struct ArrayHelper<P*> { typedef StructPointer<P> ElementType; static size_t ComputeSizeOfElements(const ArrayHeader* header, const ElementType* elements) { size_t result = 0; for (uint32_t i = 0; i < header->num_elements; ++i) result += ComputeSizeOf(elements[i].ptr); return result; } static void CloneElements(const ArrayHeader* header, ElementType* elements, Buffer* buf) { for (uint32_t i = 0; i < header->num_elements; ++i) elements[i].ptr = Clone(elements[i].ptr, buf); } static void EncodePointersAndHandles(const ArrayHeader* header, ElementType* elements, std::vector<Handle>* handles) { for (uint32_t i = 0; i < header->num_elements; ++i) Encode(&elements[i], handles); } static bool DecodePointersAndHandles(const ArrayHeader* header, ElementType* elements, Message* message) { for (uint32_t i = 0; i < header->num_elements; ++i) { if (!Decode(&elements[i], message)) return false; } return true; } }; template <typename T> class ObjectTraits<Array_Data<T> > { public: static size_t ComputeSizeOf(const Array_Data<T>* array) { return Align(array->header_.num_bytes) + ArrayHelper<T>::ComputeSizeOfElements(&array->header_, array->storage()); } static Array_Data<T>* Clone(const Array_Data<T>* array, Buffer* buf) { Array_Data<T>* clone = Array_Data<T>::New(array->header_.num_elements, buf); memcpy(clone->storage(), array->storage(), array->header_.num_bytes - sizeof(Array_Data<T>)); ArrayHelper<T>::CloneElements(&clone->header_, clone->storage(), buf); return clone; } static void CloseHandles(Array_Data<T>* array) { // TODO(darin): Implement! } static void EncodePointersAndHandles(Array_Data<T>* array, std::vector<Handle>* handles) { ArrayHelper<T>::EncodePointersAndHandles(&array->header_, array->storage(), handles); } static bool DecodePointersAndHandles(Array_Data<T>* array, Message* message) { return ArrayHelper<T>::DecodePointersAndHandles(&array->header_, array->storage(), message); } }; } // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_