/*
* Copyright 2011, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(SERIALIZE_H)
#define SERIALIZE_H
#include "traits.h"
#include <algorithm>
#include <vector>
#include "utils/rsl_assert.h"
#include <string.h>
#include <stdint.h>
#include <stddef.h>
namespace detail {
inline bool is_host_little_endian() {
unsigned long one = 0x1UL;
return *reinterpret_cast<unsigned char *>(&one);
}
inline void swap_byte_order(unsigned char (&array)[1]) {
// Nothing to do
}
inline void swap_byte_order(unsigned char (&array)[2]) {
std::swap(array[0], array[1]);
}
inline void swap_byte_order(unsigned char (&array)[4]) {
std::swap(array[0], array[3]);
std::swap(array[1], array[2]);
}
inline void swap_byte_order(unsigned char (&array)[8]) {
std::swap(array[0], array[7]);
std::swap(array[1], array[6]);
std::swap(array[2], array[5]);
std::swap(array[3], array[4]);
}
}
template <bool isArchiveLittleEndian>
class ArchiveReader {
private:
unsigned char const *buf_begin;
unsigned char const *buf_end;
unsigned char const *cursor;
unsigned char const *cursor_base;
bool good;
public:
ArchiveReader(unsigned char const *buf = NULL, size_t size = 0)
: buf_begin(buf), buf_end(buf + size),
cursor(buf), cursor_base(NULL), good(buf != NULL) {
}
void prologue(size_t size) {
rsl_assert(cursor_base == NULL);
cursor_base = cursor;
}
void epilogue(size_t size) {
rsl_assert(cursor_base != NULL);
rsl_assert(cursor_base + size >= cursor);
cursor = cursor_base + size;
cursor_base = NULL;
}
void seek(off_t off, bool from_begin = false) {
if (from_begin) {
cursor = buf_begin + off;
} else {
cursor += off;
}
}
void readBytes(void *array, size_t size) {
if (!good || cursor + size > buf_end) {
good = false;
} else {
memcpy(array, cursor, size);
}
}
template <size_t size>
void operator&(char (&array)[size]) {
readBytes(array, size);
seek(size);
}
template <size_t size>
void operator&(unsigned char (&array)[size]) {
readBytes(array, size);
seek(size);
}
template <typename T>
void operator&(T &v) {
seekAlignment<T>();
readBytes(&v, TypeTraits<T>::size);
seek(TypeTraits<T>::size);
if (isArchiveLittleEndian != detail::is_host_little_endian()) {
detail::swap_byte_order(
reinterpret_cast<unsigned char (&)[TypeTraits<T>::size]>(v));
}
}
operator void const *() const {
return good ? this : 0;
}
bool operator!() const {
return !good;
}
private:
template <typename T>
void seekAlignment() {
size_t align = TypeTraits<T>::align;
size_t delta = static_cast<size_t>(cursor - buf_begin) % align;
if (delta > 0) {
seek(align - delta);
}
}
};
typedef ArchiveReader<true> ArchiveReaderLE;
typedef ArchiveReader<false> ArchiveReaderBE;
#endif // SERIALIZE_H