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::order) bits> 199 struct what; 200 201 template <> 202 struct what<boost::endian::order::little> 203 { isboost::spirit::qi::detail::what204 static char const* is() 205 { 206 return "little-endian binary"; 207 } 208 }; 209 210 template <> 211 struct what<boost::endian::order::big> 212 { isboost::spirit::qi::detail::what213 static char const* is() 214 { 215 return "big-endian binary"; 216 } 217 }; 218 } 219 220 /////////////////////////////////////////////////////////////////////////// 221 template <typename T, BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits> 222 struct any_binary_parser : primitive_parser<any_binary_parser<T, endian, bits> > 223 { 224 template <typename Context, typename Iterator> 225 struct attribute 226 { 227 typedef boost::endian::endian_arithmetic<endian, typename T::type, 228 bits> type; 229 }; 230 231 template <typename Iterator, typename Context 232 , typename Skipper, typename Attribute> parseboost::spirit::qi::any_binary_parser233 bool parse(Iterator& first, Iterator const& last 234 , Context& /*context*/, Skipper const& skipper 235 , Attribute& attr_param) const 236 { 237 qi::skip_over(first, last, skipper); 238 239 typename attribute<Context, Iterator>::type attr_; 240 unsigned char* bytes = attr_.data(); 241 242 Iterator it = first; 243 for (unsigned int i = 0; i < sizeof(attr_); ++i) 244 { 245 if (it == last) 246 return false; 247 *bytes++ = *it++; 248 } 249 250 first = it; 251 spirit::traits::assign_to(attr_, attr_param); 252 return true; 253 } 254 255 template <typename Context> whatboost::spirit::qi::any_binary_parser256 info what(Context& /*context*/) const 257 { 258 return info(qi::detail::what<endian>::is()); 259 } 260 }; 261 262 /////////////////////////////////////////////////////////////////////////// 263 template <typename V, typename T 264 , BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits> 265 struct binary_lit_parser 266 : primitive_parser<binary_lit_parser<V, T, endian, bits> > 267 { 268 template <typename Context, typename Iterator> 269 struct attribute 270 { 271 typedef unused_type type; 272 }; 273 binary_lit_parserboost::spirit::qi::binary_lit_parser274 binary_lit_parser(V n_) 275 : n(n_) {} 276 277 template <typename Iterator, typename Context 278 , typename Skipper, typename Attribute> parseboost::spirit::qi::binary_lit_parser279 bool parse(Iterator& first, Iterator const& last 280 , Context& /*context*/, Skipper const& skipper 281 , Attribute& attr_param) const 282 { 283 qi::skip_over(first, last, skipper); 284 285 boost::endian::endian_arithmetic<endian, typename T::type, bits> attr_; 286 287 #if defined(BOOST_MSVC) 288 // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data 289 #pragma warning(push) 290 #pragma warning(disable: 4244) 291 #endif 292 attr_ = n; 293 #if defined(BOOST_MSVC) 294 #pragma warning(pop) 295 #endif 296 297 unsigned char* bytes = attr_.data(); 298 299 Iterator it = first; 300 for (unsigned int i = 0; i < sizeof(attr_); ++i) 301 { 302 if (it == last || *bytes++ != static_cast<unsigned char>(*it++)) 303 return false; 304 } 305 306 first = it; 307 spirit::traits::assign_to(attr_, attr_param); 308 return true; 309 } 310 311 template <typename Context> whatboost::spirit::qi::binary_lit_parser312 info what(Context& /*context*/) const 313 { 314 return info(qi::detail::what<endian>::is()); 315 } 316 317 V n; 318 }; 319 320 /////////////////////////////////////////////////////////////////////////// 321 // Parser generators: make_xxx function (objects) 322 /////////////////////////////////////////////////////////////////////////// 323 template <typename T, BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits> 324 struct make_binary_parser 325 { 326 typedef any_binary_parser<T, endian, bits> result_type; operator ()boost::spirit::qi::make_binary_parser327 result_type operator()(unused_type, unused_type) const 328 { 329 return result_type(); 330 } 331 }; 332 333 template <typename V, typename T 334 , BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits> 335 struct make_binary_lit_parser 336 { 337 typedef binary_lit_parser<V, T, endian, bits> result_type; 338 template <typename Terminal> operator ()boost::spirit::qi::make_binary_lit_parser339 result_type operator()(Terminal const& term, unused_type) const 340 { 341 return result_type(fusion::at_c<0>(term.args)); 342 } 343 }; 344 345 #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \ 346 template <typename Modifiers> \ 347 struct make_primitive<tag::name, Modifiers> \ 348 : make_binary_parser<detail::integer<bits>, \ 349 boost::endian::order::endiantype, bits> {}; \ 350 \ 351 template <typename Modifiers, typename A0> \ 352 struct make_primitive< \ 353 terminal_ex<tag::name, fusion::vector1<A0> > , Modifiers> \ 354 : make_binary_lit_parser<A0, detail::integer<bits>, \ 355 boost::endian::order::endiantype, bits> {}; \ 356 \ 357 /***/ 358 359 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8) 360 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16) 361 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16) 362 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16) 363 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32) 364 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32) 365 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32) 366 #ifdef BOOST_HAS_LONG_LONG 367 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64) 368 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64) 369 BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64) 370 #endif 371 372 #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE 373 374 #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \ 375 template<typename Modifiers> \ 376 struct make_primitive<tag::name, Modifiers> \ 377 : make_binary_parser<detail::floating_point<bits>, \ 378 boost::endian::order::endiantype, bits> {}; \ 379 \ 380 template<typename Modifiers, typename A0> \ 381 struct make_primitive< \ 382 terminal_ex<tag::name, fusion::vector1<A0> >, Modifiers> \ 383 : make_binary_lit_parser<A0, detail::floating_point<bits>, \ 384 boost::endian::order::endiantype, \ 385 bits> {}; \ 386 \ 387 /***/ 388 389 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32) 390 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32) 391 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32) 392 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64) 393 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64) 394 BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64) 395 396 #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE 397 398 }}} 399 400 #endif 401