1 /* net6 - Library providing IPv4/IPv6 network access
2 * Copyright (C) 2005, 2006 Armin Burgmeier / 0x539 dev group
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef _NET6_SERIALISE_HPP_
20 #define _NET6_SERIALISE_HPP_
21
22 #include <string>
23 #include <sstream>
24 #include <stdexcept>
25
26 /** Generic stuff to de/serialise data types to/from strings.
27 */
28 namespace serialise
29 {
30
31 /** Error that is thrown if conversion from a string fails. For example, if
32 * "t3" should be converted to int.
33 */
34 class conversion_error: public std::runtime_error
35 {
36 public:
37 conversion_error(const std::string& message);
38 };
39
40 /** @brief Several built-in type names.
41 */
42 template<typename data_type> struct type_name {};
43
44 template<> struct type_name<int> { static const char* name; };
45 template<> struct type_name<long> { static const char* name; };
46 template<> struct type_name<short> { static const char* name; };
47 template<> struct type_name<char> { static const char* name; };
48 template<> struct type_name<unsigned int> { static const char* name; };
49 template<> struct type_name<unsigned long> { static const char* name; };
50 template<> struct type_name<unsigned short> { static const char* name; };
51 template<> struct type_name<unsigned char> { static const char* name; };
52 template<> struct type_name<float> { static const char* name; };
53 template<> struct type_name<double> { static const char* name; };
54 template<> struct type_name<long double> { static const char* name; };
55 template<> struct type_name<bool> { static const char* name; };
56
57 /** Abstract base context type to convert something to a string.
58 */
59 template<typename data_type>
60 class context_base_to
61 {
62 public:
~context_base_to()63 virtual ~context_base_to() {}
64
65 /** @brief Converts the given data type to a string.
66 */
67 virtual std::string to_string(const data_type& from) const = 0;
68 };
69
70 /** Abstract base context type to convert a string to another type.
71 */
72 template<typename data_type>
73 class context_base_from
74 {
75 public:
~context_base_from()76 virtual ~context_base_from() {}
77
78 /** @brief Converts a string to a data type. Might throw
79 * serialise::conversion_error.
80 */
81 virtual data_type from_string(const std::string& from) const = 0;
82 };
83
84 /** Default context to convert something literally to a string.
85 */
86 template<typename data_type>
87 class default_context_to: public context_base_to<data_type>
88 {
89 public:
90 /** @brief Converts the given data type to a string.
91 */
92 virtual std::string to_string(const data_type& from) const;
93
94 protected:
95 /** Method derived classes may overload to alter the conversion.
96 */
97 virtual void on_stream_setup(std::stringstream& stream) const;
98 };
99
100 /** Default context to convert a string literally to a type.
101 */
102 template<typename data_type>
103 class default_context_from: public context_base_from<data_type>
104 {
105 public:
106 /** @brief Converts the given string to the type specified
107 * as template parameter.
108 *
109 * May throw serialise::conversion_error().
110 */
111 virtual data_type from_string(const std::string& from) const;
112
113 protected:
114 /** Method derived classes may overload to alter the conversion.
115 */
116 virtual void on_stream_setup(std::stringstream& stream) const;
117 };
118
119 /** Context that uses hexadecimal representation for numerical types.
120 */
121 template<typename data_type>
122 class hex_context_to: public default_context_to<data_type>
123 {
124 protected:
125 virtual void on_stream_setup(std::stringstream& stream) const;
126 };
127
128 /** Context that uses hexadecimal representation for numerical types.
129 */
130 template<typename data_type>
131 class hex_context_from: public default_context_from<data_type>
132 {
133 public:
134 virtual void on_stream_setup(std::stringstream& stream) const;
135 };
136
137 template<>
138 class default_context_to<std::string>: public context_base_to<std::string>
139 {
140 public:
141 typedef std::string data_type;
142
143 virtual std::string to_string(const data_type& from) const;
144 };
145
146 template<>
147 class default_context_from<std::string>: public context_base_from<std::string>
148 {
149 public:
150 typedef std::string data_type;
151
152 virtual data_type from_string(const std::string& from) const;
153 };
154
155 template<>
156 class default_context_to<const char*>: public context_base_to<const char*>
157 {
158 public:
159 typedef const char* data_type;
160
161 virtual std::string to_string(const data_type& from) const;
162 };
163
164 template<std::size_t N>
165 class default_context_to<char[N]>: public context_base_to<char[N]>
166 {
167 public:
168 typedef char data_type[N];
169
170 virtual std::string to_string(const data_type& from) const;
171 };
172
173 #if 0
174 /** String serialisation does not need any conversions.
175 */
176 template<>
177 class context<std::string>: public context_base<std::string>
178 {
179 public:
180 typedef std::string data_type;
181
182 virtual std::string to_string(const data_type& from) const;
183 virtual data_type from_string(const std::string& string) const;
184 };
185
186 /** const char* serialisation is only supported in one direction
187 * (const char* -> string). If you want to get certain data as const char*,
188 * get it as std::string and call c_str() on it.
189 */
190 template<>
191 class context<const char*>: public context_base<const char*>
192 {
193 public:
194 typedef const char* data_type;
195
196 virtual std::string to_string(const data_type& from) const;
197
198 /** This method must not be instanciated. Use context<std::string>
199 * instead!
200 */
201 virtual data_type from_string(const std::string& from) const;
202 };
203
204 /** char array serialisation is only supported in one direction
205 * (char[N] -> string). If you want to get certain data as a char array, get
206 * it as std::string and call c_str() on it.
207 */
208 template<size_t N>
209 class context<char[N]>: public context_base<char[N]>
210 {
211 public:
212 typedef const char data_type[N];
213
214 virtual std::string to_string(const data_type& from) const;
215
216 /** This method must not be instanciated. Use context<std::string>
217 * instead!
218 */
219 virtual data_type from_string(const std::string& from) const;
220 };
221 #endif
222
223 /** A serialised object.
224 */
225 class data
226 {
227 public:
228 /** Uses the given string as serialised data without converting it.
229 */
230 data(const std::string& serialised);
231
232 /** Serialises the given object with the given context. A default
233 * context is used if no one is given.
234 */
235 template<typename type>
236 data(const type& data,
237 const context_base_to<type>& ctx = default_context_to<type>());
238
239 /** Returns the serialised data.
240 */
241 const std::string& serialised() const;
242
243 /** Deserialises the object with the given context. A default context
244 * is used of no one is given.
245 */
246 template<typename type>
247 type as(const context_base_from<type>& ctx =
248 default_context_from<type>()) const;
249
250 protected:
251 std::string m_serialised;
252 };
253
254 template<typename data_type>
255 std::string default_context_to<data_type>::
to_string(const data_type & from) const256 to_string(const data_type& from) const
257 {
258 std::stringstream stream;
259 on_stream_setup(stream);
260 stream << from;
261 return stream.str();
262 }
263
264 template<typename data_type>
265 data_type default_context_from<data_type>::
from_string(const std::string & from) const266 from_string(const std::string& from) const
267 {
268 std::stringstream stream(from);
269 on_stream_setup(stream);
270 data_type data;
271 stream >> data;
272
273 if(stream.bad() )
274 {
275 throw conversion_error(
276 "Could not convert \"" + from + "\" to " +
277 type_name<data_type>::name
278 );
279 }
280
281 return data;
282 }
283
284 template<typename data_type>
285 void default_context_to<data_type>::
on_stream_setup(std::stringstream & stream) const286 on_stream_setup(std::stringstream& stream) const
287 {
288 }
289
290 template<typename data_type>
291 void default_context_from<data_type>::
on_stream_setup(std::stringstream & stream) const292 on_stream_setup(std::stringstream& stream) const
293 {
294 }
295
296 template<typename data_type>
297 void hex_context_to<data_type>::
on_stream_setup(std::stringstream & stream) const298 on_stream_setup(std::stringstream& stream) const
299 {
300 stream << std::hex;
301 }
302
303 template<typename data_type>
304 void hex_context_from<data_type>::
on_stream_setup(std::stringstream & stream) const305 on_stream_setup(std::stringstream& stream) const
306 {
307 stream >> std::hex;
308 }
309
310 template<typename data_type>
data(const data_type & data,const context_base_to<data_type> & ctx)311 data::data(const data_type& data, const context_base_to<data_type>& ctx):
312 m_serialised(ctx.to_string(data) )
313 {
314 }
315
316 template<typename data_type>
as(const context_base_from<data_type> & ctx) const317 data_type data::as(const context_base_from<data_type>& ctx) const
318 {
319 return ctx.from_string(m_serialised);
320 }
321
322 template<size_t N>
323 std::string default_context_to<char[N]>::
to_string(const data_type & from) const324 to_string(const data_type& from) const
325 {
326 return from;
327 }
328
329 } // namespace serialise
330
331 #endif // _NET6_SERIALISE_HPP_
332