C++程序  |  231行  |  7.44 KB

// 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_