comparison C++/Pack.h @ 185:523156bb3af5

Add Pack class Task: #213
author David Demelier <markand@malikania.fr>
date Fri, 15 Nov 2013 21:37:57 +0100
parents
children 8fc177bbc4a6
comparison
equal deleted inserted replaced
184:4c746050969a 185:523156bb3af5
1 /*
2 * Pack.h -- binary data serialization
3 *
4 * Copyright (c) 2013 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifndef _PACK_H_
20 #define _PACK_H_
21
22 #include <cstdint>
23 #include <fstream>
24 #include <stdexcept>
25 #include <string>
26
27 /**
28 * @class Pack
29 * @brief Serialize binary data to files
30 *
31 * This class write and read binary data from files. It currently
32 * support:
33 * uint8_t,
34 * uint16_t,
35 * uint32_t,
36 * uint64_t
37 */
38 class Pack {
39 public:
40 /**
41 * @enum Endian
42 * @brief Endian mode
43 */
44 enum Endian {
45 Little, //! Little endian
46 Big //! Big endian
47 };
48
49 private:
50 static void writeFile(std::ofstream &out, Endian endian)
51 {
52 // dummy, stop recursion
53 }
54
55 template <typename T, typename... Args>
56 static void writeFile(std::ofstream &out, Endian endian, const T &value, Args&... args)
57 {
58 static_assert(TypeInfo<T>::supported, "unsupported type");
59
60 T ret = convert(value, endian);
61 out.write(reinterpret_cast<char *>(&ret), TypeInfo<T>::size);
62 writeFile(out, endian, args...);
63 }
64
65 static void readFile(std::ifstream &in, Endian endian)
66 {
67 // dummy, stop recursion
68 }
69
70 template <typename T, typename... Args>
71 static void readFile(std::ifstream &in, Endian endian, T &value, Args&&... args)
72 {
73 static_assert(TypeInfo<T>::supported, "unsupported type");
74
75 in.read(reinterpret_cast<char *>(&value), TypeInfo<T>::size);
76 value = convert(value, endian);
77 readFile(in, endian, args...);
78 }
79
80 public:
81 static const Endian mode;
82
83 /**
84 * @struct TypeInfo
85 * @brief Type information
86 *
87 * Used for conversions.
88 */
89 template <typename T>
90 struct TypeInfo {
91 static const bool supported = false;
92 static const size_t size = 0;
93 };
94
95 /**
96 * Convert data.
97 *
98 * @param value the value to convert if needed
99 * @param endian the endian mode
100 * @return the converted value
101 */
102 template <typename T>
103 static T convert(T value, Endian endian);
104
105 /**
106 * Write binary data to the file
107 *
108 * @param path the path to the file
109 * @param endian the endian mode
110 * @param args the arguments
111 * @throw std::runtime_exception on error
112 */
113 template <typename... Args>
114 static void write(const std::string &path,
115 Endian endian,
116 Args&&... args)
117 {
118 std::ofstream out;
119
120 out.open(path, std::ios_base::binary);
121 if (!out.is_open())
122 throw std::runtime_error("Can't open file for writing");
123
124 writeFile(out, endian, std::forward<Args>(args)...);
125 }
126
127 /**
128 * Read binary data from the file
129 *
130 * @param path the path to the file
131 * @param endian the endian mode
132 * @param args the arguments
133 * @throw std::runtime_exception on error
134 */
135 template <typename... Args>
136 static void read(const std::string &path,
137 Endian endian,
138 Args&&... args)
139 {
140 std::ifstream in;
141
142 in.open(path, std::ios_base::binary);
143 if (!in.is_open())
144 throw std::runtime_error("Can't open file for reading");
145
146 readFile(in, endian, std::forward<Args>(args)...);
147 }
148 };
149
150 template <>
151 struct Pack::TypeInfo<uint8_t> {
152 static const bool supported = true;
153 static const size_t size = 1;
154 };
155
156 template <>
157 struct Pack::TypeInfo<uint16_t> {
158 static const bool supported = true;
159 static const size_t size = 2;
160 };
161
162 template <>
163 struct Pack::TypeInfo<uint32_t> {
164 static const bool supported = true;
165 static const size_t size = 4;
166 };
167
168 template <>
169 struct Pack::TypeInfo<uint64_t> {
170 static const bool supported = true;
171 static const size_t size = 8;
172 };
173
174 template <>
175 uint8_t Pack::convert(uint8_t v, Endian)
176 {
177 return v;
178 }
179
180 template <>
181 uint16_t Pack::convert(uint16_t v, Endian endian)
182 {
183 if (mode != endian)
184 return (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
185
186 return v;
187 }
188
189 template <>
190 uint32_t Pack::convert(uint32_t v, Endian endian)
191 {
192 if (mode != endian)
193 return ((((v) >> 24) & 0x000000FFL)
194 | (((v) >> 8) & 0x0000FF00L)
195 | (((v) << 8) & 0x00FF0000L)
196 | (((v) << 24) & 0xFF000000L));
197
198 return v;
199 }
200
201 template <>
202 uint64_t Pack::convert(uint64_t v, Endian endian)
203 {
204 if (mode != endian)
205 return ((((v) & 0xff00000000000000ull) >> 56)
206 | (((v) & 0x00ff000000000000ull) >> 40)
207 | (((v) & 0x0000ff0000000000ull) >> 24)
208 | (((v) & 0x000000ff00000000ull) >> 8 )
209 | (((v) & 0x00000000ff000000ull) << 8 )
210 | (((v) & 0x0000000000ff0000ull) << 24)
211 | (((v) & 0x000000000000ff00ull) << 40)
212 | (((v) & 0x00000000000000ffull) << 56));
213
214 return v;
215 }
216
217 #endif // !_PACK_H_