serialize.h revision 71e5a4a2fa18ff55b1e04e73b70b2938150a143c
1#if !defined(SERIALIZE_H)
2#define SERIALIZE_H
3
4#include "traits.h"
5
6#include <algorithm>
7#include <vector>
8
9#include <assert.h>
10#include <string.h>
11#include <stdint.h>
12#include <stddef.h>
13
14namespace detail {
15  inline bool is_host_little_endian() {
16    unsigned long one = 0x1UL;
17    return *reinterpret_cast<unsigned char *>(&one);
18  }
19
20  inline void swap_byte_order(unsigned char (&array)[1]) {
21    // Nothing to do
22  }
23
24  inline void swap_byte_order(unsigned char (&array)[2]) {
25    std::swap(array[0], array[1]);
26  }
27
28  inline void swap_byte_order(unsigned char (&array)[4]) {
29    std::swap(array[0], array[3]);
30    std::swap(array[1], array[2]);
31  }
32
33  inline void swap_byte_order(unsigned char (&array)[8]) {
34    std::swap(array[0], array[7]);
35    std::swap(array[1], array[6]);
36    std::swap(array[2], array[5]);
37    std::swap(array[3], array[4]);
38  }
39}
40
41
42template <bool isArchiveLittleEndian>
43class ArchiveReader {
44private:
45  unsigned char const *buf_begin;
46  unsigned char const *buf_end;
47  unsigned char const *cursor;
48  unsigned char const *cursor_base;
49
50  bool good;
51
52public:
53  ArchiveReader(unsigned char const *buf = NULL, size_t size = 0)
54  : buf_begin(buf), buf_end(buf + size),
55    cursor(buf), cursor_base(NULL), good(buf != NULL) {
56  }
57
58  void prologue(size_t size) {
59    assert(cursor_base == NULL);
60    cursor_base = cursor;
61  }
62
63  void epilogue(size_t size) {
64    assert(cursor_base != NULL);
65    assert(cursor_base + size >= cursor);
66    cursor = cursor_base + size;
67    cursor_base = NULL;
68  }
69
70  void seek(off_t off, bool from_begin = false) {
71    if (from_begin) {
72      cursor = buf_begin + off;
73    } else {
74      cursor += off;
75    }
76  }
77
78  void readBytes(void *array, size_t size) {
79    if (!good || cursor + size > buf_end) {
80      good = false;
81    } else {
82      memcpy(array, cursor, size);
83    }
84  }
85
86  template <size_t size>
87  void operator&(char (&array)[size]) {
88    readBytes(array, size);
89    seek(size);
90  }
91
92  template <size_t size>
93  void operator&(unsigned char (&array)[size]) {
94    readBytes(array, size);
95    seek(size);
96  }
97
98  template <typename T>
99  void operator&(T &v) {
100    seekAlignment<T>();
101    readBytes(&v, TypeTraits<T>::size);
102    seek(TypeTraits<T>::size);
103
104    if (isArchiveLittleEndian != detail::is_host_little_endian()) {
105      detail::swap_byte_order(
106        reinterpret_cast<unsigned char (&)[TypeTraits<T>::size]>(v));
107    }
108  }
109
110  operator void const *() const {
111    return good ? this : 0;
112  }
113
114  bool operator!() const {
115    return !good;
116  }
117
118private:
119  template <typename T>
120  void seekAlignment() {
121    size_t align = TypeTraits<T>::align;
122    size_t delta = static_cast<size_t>(cursor - buf_begin) % align;
123
124    if (delta > 0) {
125      seek(align - delta);
126    }
127  }
128
129};
130
131typedef ArchiveReader<true>  ArchiveReaderLE;
132typedef ArchiveReader<false> ArchiveReaderBE;
133
134#endif // SERIALIZE_H
135