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