1/*
2 * Copyright 2011, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#if !defined(SERIALIZE_H)
18#define SERIALIZE_H
19
20#include "traits.h"
21
22#include <algorithm>
23#include <vector>
24
25#include "utils/rsl_assert.h"
26#include <string.h>
27#include <stdint.h>
28#include <stddef.h>
29
30namespace detail {
31  inline bool is_host_little_endian() {
32    unsigned long one = 0x1UL;
33    return *reinterpret_cast<unsigned char *>(&one);
34  }
35
36  inline void swap_byte_order(unsigned char (&array)[1]) {
37    // Nothing to do
38  }
39
40  inline void swap_byte_order(unsigned char (&array)[2]) {
41    std::swap(array[0], array[1]);
42  }
43
44  inline void swap_byte_order(unsigned char (&array)[4]) {
45    std::swap(array[0], array[3]);
46    std::swap(array[1], array[2]);
47  }
48
49  inline void swap_byte_order(unsigned char (&array)[8]) {
50    std::swap(array[0], array[7]);
51    std::swap(array[1], array[6]);
52    std::swap(array[2], array[5]);
53    std::swap(array[3], array[4]);
54  }
55}
56
57
58template <bool isArchiveLittleEndian>
59class ArchiveReader {
60private:
61  unsigned char const *buf_begin;
62  unsigned char const *buf_end;
63  unsigned char const *cursor;
64  unsigned char const *cursor_base;
65
66  bool good;
67
68public:
69  ArchiveReader(unsigned char const *buf = NULL, size_t size = 0)
70  : buf_begin(buf), buf_end(buf + size),
71    cursor(buf), cursor_base(NULL), good(buf != NULL) {
72  }
73
74  void prologue(size_t size) {
75    rsl_assert(cursor_base == NULL);
76    cursor_base = cursor;
77  }
78
79  void epilogue(size_t size) {
80    rsl_assert(cursor_base != NULL);
81    rsl_assert(cursor_base + size >= cursor);
82    cursor = cursor_base + size;
83    cursor_base = NULL;
84  }
85
86  void seek(off_t off, bool from_begin = false) {
87    if (from_begin) {
88      cursor = buf_begin + off;
89    } else {
90      cursor += off;
91    }
92  }
93
94  void readBytes(void *array, size_t size) {
95    if (!good || cursor + size > buf_end) {
96      good = false;
97    } else {
98      memcpy(array, cursor, size);
99    }
100  }
101
102  template <size_t size>
103  void operator&(char (&array)[size]) {
104    readBytes(array, size);
105    seek(size);
106  }
107
108  template <size_t size>
109  void operator&(unsigned char (&array)[size]) {
110    readBytes(array, size);
111    seek(size);
112  }
113
114  template <typename T>
115  void operator&(T &v) {
116    seekAlignment<T>();
117    readBytes(&v, TypeTraits<T>::size);
118    seek(TypeTraits<T>::size);
119
120    if (isArchiveLittleEndian != detail::is_host_little_endian()) {
121      detail::swap_byte_order(
122        reinterpret_cast<unsigned char (&)[TypeTraits<T>::size]>(v));
123    }
124  }
125
126  operator void const *() const {
127    return good ? this : 0;
128  }
129
130  bool operator!() const {
131    return !good;
132  }
133
134private:
135  template <typename T>
136  void seekAlignment() {
137    size_t align = TypeTraits<T>::align;
138    size_t delta = static_cast<size_t>(cursor - buf_begin) % align;
139
140    if (delta > 0) {
141      seek(align - delta);
142    }
143  }
144
145};
146
147typedef ArchiveReader<true>  ArchiveReaderLE;
148typedef ArchiveReader<false> ArchiveReaderBE;
149
150#endif // SERIALIZE_H
151