]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Hartmut Kaiser | |
3 | Copyright (c) 2001-2011 Joel de Guzman | |
4 | ||
5 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
6 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ==============================================================================*/ | |
8 | #if !defined(BOOST_SPIRIT_BINARY_MAY_08_2007_0808AM) | |
9 | #define BOOST_SPIRIT_BINARY_MAY_08_2007_0808AM | |
10 | ||
11 | #if defined(_MSC_VER) | |
12 | #pragma once | |
13 | #endif | |
14 | ||
15 | #include <boost/spirit/home/support/common_terminals.hpp> | |
16 | #include <boost/spirit/home/support/detail/endian.hpp> | |
17 | #include <boost/spirit/home/qi/detail/attributes.hpp> | |
18 | #include <boost/spirit/home/qi/parser.hpp> | |
19 | #include <boost/spirit/home/qi/meta_compiler.hpp> | |
20 | #include <boost/spirit/home/qi/domain.hpp> | |
21 | #include <boost/spirit/home/qi/detail/assign_to.hpp> | |
22 | #include <boost/spirit/home/qi/skip_over.hpp> | |
23 | #include <boost/spirit/home/support/common_terminals.hpp> | |
24 | #include <boost/fusion/include/at.hpp> | |
25 | #include <boost/mpl/or.hpp> | |
26 | #include <boost/type_traits/is_integral.hpp> | |
27 | #include <boost/type_traits/is_enum.hpp> | |
28 | #include <boost/type_traits/is_floating_point.hpp> | |
29 | #include <boost/config.hpp> | |
30 | ||
31 | #define BOOST_SPIRIT_ENABLE_BINARY(name) \ | |
32 | template <> \ | |
33 | struct use_terminal<qi::domain, tag::name> \ | |
34 | : mpl::true_ {}; \ | |
35 | \ | |
36 | template <typename A0> \ | |
37 | struct use_terminal<qi::domain \ | |
38 | , terminal_ex<tag::name, fusion::vector1<A0> > > \ | |
39 | : mpl::or_<is_integral<A0>, is_enum<A0> > {}; \ | |
40 | \ | |
41 | template <> \ | |
42 | struct use_lazy_terminal<qi::domain, tag::name, 1> : mpl::true_ {}; \ | |
43 | \ | |
44 | /***/ | |
45 | ||
46 | #define BOOST_SPIRIT_ENABLE_BINARY_IEEE754(name) \ | |
47 | template<> \ | |
48 | struct use_terminal<qi::domain, tag::name>: mpl::true_ {}; \ | |
49 | \ | |
50 | template<typename A0> \ | |
51 | struct use_terminal<qi::domain, terminal_ex<tag::name, \ | |
52 | fusion::vector1<A0> > >: is_floating_point<A0> {}; \ | |
53 | \ | |
54 | template<> \ | |
55 | struct use_lazy_terminal<qi::domain, tag::name, 1>: mpl::true_ {}; \ | |
56 | \ | |
57 | /***/ | |
58 | ||
59 | namespace boost { namespace spirit | |
60 | { | |
61 | /////////////////////////////////////////////////////////////////////////// | |
62 | // Enablers | |
63 | /////////////////////////////////////////////////////////////////////////// | |
64 | BOOST_SPIRIT_ENABLE_BINARY(byte_) // enables byte_ | |
65 | BOOST_SPIRIT_ENABLE_BINARY(word) // enables word | |
66 | BOOST_SPIRIT_ENABLE_BINARY(big_word) // enables big_word | |
67 | BOOST_SPIRIT_ENABLE_BINARY(little_word) // enables little_word | |
68 | BOOST_SPIRIT_ENABLE_BINARY(dword) // enables dword | |
69 | BOOST_SPIRIT_ENABLE_BINARY(big_dword) // enables big_dword | |
70 | BOOST_SPIRIT_ENABLE_BINARY(little_dword) // enables little_dword | |
71 | #ifdef BOOST_HAS_LONG_LONG | |
72 | BOOST_SPIRIT_ENABLE_BINARY(qword) // enables qword | |
73 | BOOST_SPIRIT_ENABLE_BINARY(big_qword) // enables big_qword | |
74 | BOOST_SPIRIT_ENABLE_BINARY(little_qword) // enables little_qword | |
75 | #endif | |
76 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_float) | |
77 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_float) | |
78 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_float) | |
79 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_double) | |
80 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_double) | |
81 | BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_double) | |
82 | }} | |
83 | ||
84 | #undef BOOST_SPIRIT_ENABLE_BINARY | |
85 | #undef BOOST_SPIRIT_ENABLE_BINARY_IEEE754 | |
86 | ||
87 | namespace boost { namespace spirit { namespace qi | |
88 | { | |
89 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS | |
90 | using boost::spirit::byte_; | |
91 | using boost::spirit::word; | |
92 | using boost::spirit::big_word; | |
93 | using boost::spirit::little_word; | |
94 | using boost::spirit::dword; | |
95 | using boost::spirit::big_dword; | |
96 | using boost::spirit::little_dword; | |
97 | #ifdef BOOST_HAS_LONG_LONG | |
98 | using boost::spirit::qword; | |
99 | using boost::spirit::big_qword; | |
100 | using boost::spirit::little_qword; | |
101 | #endif | |
102 | using boost::spirit::bin_float; | |
103 | using boost::spirit::big_bin_float; | |
104 | using boost::spirit::little_bin_float; | |
105 | using boost::spirit::bin_double; | |
106 | using boost::spirit::big_bin_double; | |
107 | using boost::spirit::little_bin_double; | |
108 | #endif | |
109 | ||
110 | using boost::spirit::byte_type; | |
111 | using boost::spirit::word_type; | |
112 | using boost::spirit::big_word_type; | |
113 | using boost::spirit::little_word_type; | |
114 | using boost::spirit::dword_type; | |
115 | using boost::spirit::big_dword_type; | |
116 | using boost::spirit::little_dword_type; | |
117 | #ifdef BOOST_HAS_LONG_LONG | |
118 | using boost::spirit::qword_type; | |
119 | using boost::spirit::big_qword_type; | |
120 | using boost::spirit::little_qword_type; | |
121 | #endif | |
122 | using boost::spirit::bin_float_type; | |
123 | using boost::spirit::big_bin_float_type; | |
124 | using boost::spirit::little_bin_float_type; | |
125 | using boost::spirit::bin_double_type; | |
126 | using boost::spirit::big_bin_double_type; | |
127 | using boost::spirit::little_bin_double_type; | |
128 | ||
129 | namespace detail | |
130 | { | |
131 | template <int bits> | |
132 | struct integer | |
133 | { | |
134 | #ifdef BOOST_HAS_LONG_LONG | |
135 | BOOST_SPIRIT_ASSERT_MSG( | |
136 | bits == 8 || bits == 16 || bits == 32 || bits == 64, | |
137 | not_supported_binary_size, ()); | |
138 | #else | |
139 | BOOST_SPIRIT_ASSERT_MSG( | |
140 | bits == 8 || bits == 16 || bits == 32, | |
141 | not_supported_binary_size, ()); | |
142 | #endif | |
143 | }; | |
144 | ||
145 | template <> | |
146 | struct integer<8> | |
147 | { | |
148 | enum { size = 1 }; | |
149 | typedef uint_least8_t type; | |
150 | }; | |
151 | ||
152 | template <> | |
153 | struct integer<16> | |
154 | { | |
155 | enum { size = 2 }; | |
156 | typedef uint_least16_t type; | |
157 | }; | |
158 | ||
159 | template <> | |
160 | struct integer<32> | |
161 | { | |
162 | enum { size = 4 }; | |
163 | typedef uint_least32_t type; | |
164 | }; | |
165 | ||
166 | #ifdef BOOST_HAS_LONG_LONG | |
167 | template <> | |
168 | struct integer<64> | |
169 | { | |
170 | enum { size = 8 }; | |
171 | typedef uint_least64_t type; | |
172 | }; | |
173 | #endif | |
174 | ||
175 | template <int bits> | |
176 | struct floating_point | |
177 | { | |
178 | BOOST_SPIRIT_ASSERT_MSG( | |
179 | bits == 32 || bits == 64, | |
180 | not_supported_binary_size, ()); | |
181 | }; | |
182 | ||
183 | template <> | |
184 | struct floating_point<32> | |
185 | { | |
186 | enum { size = 4 }; | |
187 | typedef float type; | |
188 | }; | |
189 | ||
190 | template <> | |
191 | struct floating_point<64> | |
192 | { | |
193 | enum { size = 8 }; | |
194 | typedef double type; | |
195 | }; | |
196 | ||
197 | /////////////////////////////////////////////////////////////////////// | |
198 | template <BOOST_SCOPED_ENUM(boost::endian::endianness) bits> | |
199 | struct what; | |
200 | ||
201 | template <> | |
202 | struct what<boost::endian::endianness::native> | |
203 | { | |
204 | static std::string is() | |
205 | { | |
206 | return "native-endian binary"; | |
207 | } | |
208 | }; | |
209 | ||
210 | template <> | |
211 | struct what<boost::endian::endianness::little> | |
212 | { | |
213 | static char const* is() | |
214 | { | |
215 | return "little-endian binary"; | |
216 | } | |
217 | }; | |
218 | ||
219 | template <> | |
220 | struct what<boost::endian::endianness::big> | |
221 | { | |
222 | static char const* is() | |
223 | { | |
224 | return "big-endian binary"; | |
225 | } | |
226 | }; | |
227 | } | |
228 | ||
229 | /////////////////////////////////////////////////////////////////////////// | |
230 | template <typename T, BOOST_SCOPED_ENUM(boost::endian::endianness) endian, int bits> | |
231 | struct any_binary_parser : primitive_parser<any_binary_parser<T, endian, bits> > | |
232 | { | |
233 | template <typename Context, typename Iterator> | |
234 | struct attribute | |
235 | { | |
236 | typedef boost::endian::endian<endian, typename T::type, | |
237 | bits> type; | |
238 | }; | |
239 | ||
240 | template <typename Iterator, typename Context | |
241 | , typename Skipper, typename Attribute> | |
242 | bool parse(Iterator& first, Iterator const& last | |
243 | , Context& /*context*/, Skipper const& skipper | |
244 | , Attribute& attr_param) const | |
245 | { | |
246 | qi::skip_over(first, last, skipper); | |
247 | ||
248 | typename attribute<Context, Iterator>::type attr_; | |
249 | unsigned char* bytes = reinterpret_cast<unsigned char*>(&attr_); | |
250 | ||
251 | Iterator it = first; | |
252 | for (unsigned int i = 0; i < sizeof(attr_); ++i) | |
253 | { | |
254 | if (it == last) | |
255 | return false; | |
256 | *bytes++ = *it++; | |
257 | } | |
258 | ||
259 | first = it; | |
260 | spirit::traits::assign_to(attr_, attr_param); | |
261 | return true; | |
262 | } | |
263 | ||
264 | template <typename Context> | |
265 | info what(Context& /*context*/) const | |
266 | { | |
267 | return info(qi::detail::what<endian>::is()); | |
268 | } | |
269 | }; | |
270 | ||
271 | /////////////////////////////////////////////////////////////////////////// | |
272 | template <typename V, typename T | |
273 | , BOOST_SCOPED_ENUM(boost::endian::endianness) endian, int bits> | |
274 | struct binary_lit_parser | |
275 | : primitive_parser<binary_lit_parser<V, T, endian, bits> > | |
276 | { | |
277 | template <typename Context, typename Iterator> | |
278 | struct attribute | |
279 | { | |
280 | typedef unused_type type; | |
281 | }; | |
282 | ||
283 | binary_lit_parser(V n_) | |
284 | : n(n_) {} | |
285 | ||
286 | template <typename Iterator, typename Context | |
287 | , typename Skipper, typename Attribute> | |
288 | bool parse(Iterator& first, Iterator const& last | |
289 | , Context& /*context*/, Skipper const& skipper | |
290 | , Attribute& attr_param) const | |
291 | { | |
292 | qi::skip_over(first, last, skipper); | |
293 | ||
294 | // Even if the endian types are not pod's (at least not in the | |
295 | // definition of C++03) it seems to be safe to assume they are | |
296 | // (but in C++0x the endian types _are_ PODs). | |
297 | // This allows us to treat them as a sequence of consecutive bytes. | |
298 | boost::endian::endian<endian, typename T::type, bits> attr_; | |
299 | ||
300 | #if defined(BOOST_MSVC) | |
301 | // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data | |
302 | #pragma warning(push) | |
303 | #pragma warning(disable: 4244) | |
304 | #endif | |
305 | attr_ = n; | |
306 | #if defined(BOOST_MSVC) | |
307 | #pragma warning(pop) | |
308 | #endif | |
309 | ||
310 | unsigned char* bytes = reinterpret_cast<unsigned char*>(&attr_); | |
311 | ||
312 | Iterator it = first; | |
313 | for (unsigned int i = 0; i < sizeof(attr_); ++i) | |
314 | { | |
315 | if (it == last || *bytes++ != static_cast<unsigned char>(*it++)) | |
316 | return false; | |
317 | } | |
318 | ||
319 | first = it; | |
320 | spirit::traits::assign_to(attr_, attr_param); | |
321 | return true; | |
322 | } | |
323 | ||
324 | template <typename Context> | |
325 | info what(Context& /*context*/) const | |
326 | { | |
327 | return info(qi::detail::what<endian>::is()); | |
328 | } | |
329 | ||
330 | V n; | |
331 | }; | |
332 | ||
333 | /////////////////////////////////////////////////////////////////////////// | |
334 | // Parser generators: make_xxx function (objects) | |
335 | /////////////////////////////////////////////////////////////////////////// | |
336 | template <typename T, BOOST_SCOPED_ENUM(boost::endian::endianness) endian, int bits> | |
337 | struct make_binary_parser | |
338 | { | |
339 | typedef any_binary_parser<T, endian, bits> result_type; | |
340 | result_type operator()(unused_type, unused_type) const | |
341 | { | |
342 | return result_type(); | |
343 | } | |
344 | }; | |
345 | ||
346 | template <typename V, typename T | |
347 | , BOOST_SCOPED_ENUM(boost::endian::endianness) endian, int bits> | |
348 | struct make_binary_lit_parser | |
349 | { | |
350 | typedef binary_lit_parser<V, T, endian, bits> result_type; | |
351 | template <typename Terminal> | |
352 | result_type operator()(Terminal const& term, unused_type) const | |
353 | { | |
354 | return result_type(fusion::at_c<0>(term.args)); | |
355 | } | |
356 | }; | |
357 | ||
358 | #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \ | |
359 | template <typename Modifiers> \ | |
360 | struct make_primitive<tag::name, Modifiers> \ | |
361 | : make_binary_parser<detail::integer<bits>, \ | |
362 | boost::endian::endianness::endiantype, bits> {}; \ | |
363 | \ | |
364 | template <typename Modifiers, typename A0> \ | |
365 | struct make_primitive< \ | |
366 | terminal_ex<tag::name, fusion::vector1<A0> > , Modifiers> \ | |
367 | : make_binary_lit_parser<A0, detail::integer<bits>, \ | |
368 | boost::endian::endianness::endiantype, bits> {}; \ | |
369 | \ | |
370 | /***/ | |
371 | ||
372 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8) | |
373 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16) | |
374 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16) | |
375 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16) | |
376 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32) | |
377 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32) | |
378 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32) | |
379 | #ifdef BOOST_HAS_LONG_LONG | |
380 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64) | |
381 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64) | |
382 | BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64) | |
383 | #endif | |
384 | ||
385 | #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE | |
386 | ||
387 | #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \ | |
388 | template<typename Modifiers> \ | |
389 | struct make_primitive<tag::name, Modifiers> \ | |
390 | : make_binary_parser<detail::floating_point<bits>, \ | |
391 | boost::endian::endianness::endiantype, bits> {}; \ | |
392 | \ | |
393 | template<typename Modifiers, typename A0> \ | |
394 | struct make_primitive< \ | |
395 | terminal_ex<tag::name, fusion::vector1<A0> >, Modifiers> \ | |
396 | : make_binary_lit_parser<A0, detail::floating_point<bits>, \ | |
397 | boost::endian::endianness::endiantype, \ | |
398 | bits> {}; \ | |
399 | \ | |
400 | /***/ | |
401 | ||
402 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32) | |
403 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32) | |
404 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32) | |
405 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64) | |
406 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64) | |
407 | BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64) | |
408 | ||
409 | #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE | |
410 | ||
411 | }}} | |
412 | ||
413 | #endif |