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