Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: Copyright (c) 2001-2011 Joel de Guzman Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: ==============================================================================*/ Chris@16: #if !defined(BOOST_SPIRIT_BINARY_MAY_08_2007_0808AM) Chris@16: #define BOOST_SPIRIT_BINARY_MAY_08_2007_0808AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #define BOOST_SPIRIT_ENABLE_BINARY(name) \ Chris@16: template <> \ Chris@16: struct use_terminal \ Chris@16: : mpl::true_ {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct use_terminal > > \ Chris@16: : mpl::or_, is_enum > {}; \ Chris@16: \ Chris@16: template <> \ Chris@16: struct use_lazy_terminal : mpl::true_ {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: #define BOOST_SPIRIT_ENABLE_BINARY_IEEE754(name) \ Chris@16: template<> \ Chris@16: struct use_terminal: mpl::true_ {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct use_terminal > >: is_floating_point {}; \ Chris@16: \ Chris@16: template<> \ Chris@16: struct use_lazy_terminal: mpl::true_ {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: namespace boost { namespace spirit Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Enablers Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: BOOST_SPIRIT_ENABLE_BINARY(byte_) // enables byte_ Chris@16: BOOST_SPIRIT_ENABLE_BINARY(word) // enables word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_word) // enables big_word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_word) // enables little_word Chris@16: BOOST_SPIRIT_ENABLE_BINARY(dword) // enables dword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_dword) // enables big_dword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_dword) // enables little_dword Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_ENABLE_BINARY(qword) // enables qword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(big_qword) // enables big_qword Chris@16: BOOST_SPIRIT_ENABLE_BINARY(little_qword) // enables little_qword Chris@16: #endif Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_float) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(bin_double) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(big_bin_double) Chris@16: BOOST_SPIRIT_ENABLE_BINARY_IEEE754(little_bin_double) Chris@16: }} Chris@16: Chris@16: #undef BOOST_SPIRIT_ENABLE_BINARY Chris@16: #undef BOOST_SPIRIT_ENABLE_BINARY_IEEE754 Chris@16: Chris@16: namespace boost { namespace spirit { namespace qi Chris@16: { Chris@16: #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS Chris@16: using boost::spirit::byte_; Chris@16: using boost::spirit::word; Chris@16: using boost::spirit::big_word; Chris@16: using boost::spirit::little_word; Chris@16: using boost::spirit::dword; Chris@16: using boost::spirit::big_dword; Chris@16: using boost::spirit::little_dword; Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: using boost::spirit::qword; Chris@16: using boost::spirit::big_qword; Chris@16: using boost::spirit::little_qword; Chris@16: #endif Chris@16: using boost::spirit::bin_float; Chris@16: using boost::spirit::big_bin_float; Chris@16: using boost::spirit::little_bin_float; Chris@16: using boost::spirit::bin_double; Chris@16: using boost::spirit::big_bin_double; Chris@16: using boost::spirit::little_bin_double; Chris@16: #endif Chris@16: Chris@16: using boost::spirit::byte_type; Chris@16: using boost::spirit::word_type; Chris@16: using boost::spirit::big_word_type; Chris@16: using boost::spirit::little_word_type; Chris@16: using boost::spirit::dword_type; Chris@16: using boost::spirit::big_dword_type; Chris@16: using boost::spirit::little_dword_type; Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: using boost::spirit::qword_type; Chris@16: using boost::spirit::big_qword_type; Chris@16: using boost::spirit::little_qword_type; Chris@16: #endif Chris@16: using boost::spirit::bin_float_type; Chris@16: using boost::spirit::big_bin_float_type; Chris@16: using boost::spirit::little_bin_float_type; Chris@16: using boost::spirit::bin_double_type; Chris@16: using boost::spirit::big_bin_double_type; Chris@16: using boost::spirit::little_bin_double_type; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct integer Chris@16: { Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 8 || bits == 16 || bits == 32 || bits == 64, Chris@16: not_supported_binary_size, ()); Chris@16: #else Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 8 || bits == 16 || bits == 32, Chris@16: not_supported_binary_size, ()); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<8> Chris@16: { Chris@16: enum { size = 1 }; Chris@16: typedef uint_least8_t type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<16> Chris@16: { Chris@16: enum { size = 2 }; Chris@16: typedef uint_least16_t type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct integer<32> Chris@16: { Chris@16: enum { size = 4 }; Chris@16: typedef uint_least32_t type; Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: template <> Chris@16: struct integer<64> Chris@16: { Chris@16: enum { size = 8 }; Chris@16: typedef uint_least64_t type; Chris@16: }; Chris@16: #endif Chris@16: Chris@16: template Chris@16: struct floating_point Chris@16: { Chris@16: BOOST_SPIRIT_ASSERT_MSG( Chris@16: bits == 32 || bits == 64, Chris@16: not_supported_binary_size, ()); Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct floating_point<32> Chris@16: { Chris@16: enum { size = 4 }; Chris@16: typedef float type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct floating_point<64> Chris@16: { Chris@16: enum { size = 8 }; Chris@16: typedef double type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct what; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static std::string is() Chris@16: { Chris@16: return "native-endian binary"; Chris@16: } Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static char const* is() Chris@16: { Chris@16: return "little-endian binary"; Chris@16: } Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct what Chris@16: { Chris@16: static char const* is() Chris@16: { Chris@16: return "big-endian binary"; Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct any_binary_parser : primitive_parser > Chris@16: { Chris@16: template Chris@16: struct attribute Chris@16: { Chris@16: typedef boost::endian::endian type; Chris@16: }; Chris@16: Chris@16: template Chris@16: bool parse(Iterator& first, Iterator const& last Chris@16: , Context& /*context*/, Skipper const& skipper Chris@16: , Attribute& attr_param) const Chris@16: { Chris@16: qi::skip_over(first, last, skipper); Chris@16: Chris@16: typename attribute::type attr_; Chris@16: unsigned char* bytes = reinterpret_cast(&attr_); Chris@16: Chris@16: Iterator it = first; Chris@16: for (unsigned int i = 0; i < sizeof(attr_); ++i) Chris@16: { Chris@16: if (it == last) Chris@16: return false; Chris@16: *bytes++ = *it++; Chris@16: } Chris@16: Chris@16: first = it; Chris@16: spirit::traits::assign_to(attr_, attr_param); Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: info what(Context& /*context*/) const Chris@16: { Chris@16: return info(qi::detail::what::is()); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct binary_lit_parser Chris@16: : primitive_parser > Chris@16: { Chris@16: template Chris@16: struct attribute Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: binary_lit_parser(V n_) Chris@16: : n(n_) {} Chris@16: Chris@16: template Chris@16: bool parse(Iterator& first, Iterator const& last Chris@16: , Context& /*context*/, Skipper const& skipper Chris@16: , Attribute& attr_param) const Chris@16: { Chris@16: qi::skip_over(first, last, skipper); Chris@16: Chris@16: // Even if the endian types are not pod's (at least not in the Chris@16: // definition of C++03) it seems to be safe to assume they are Chris@16: // (but in C++0x the endian types _are_ PODs). Chris@16: // This allows us to treat them as a sequence of consecutive bytes. Chris@16: boost::endian::endian attr_; Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable: 4244) Chris@16: #endif Chris@16: attr_ = n; Chris@16: #if defined(BOOST_MSVC) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: unsigned char* bytes = reinterpret_cast(&attr_); Chris@16: Chris@16: Iterator it = first; Chris@16: for (unsigned int i = 0; i < sizeof(attr_); ++i) Chris@16: { Chris@16: if (it == last || *bytes++ != static_cast(*it++)) Chris@16: return false; Chris@16: } Chris@16: Chris@16: first = it; Chris@16: spirit::traits::assign_to(attr_, attr_param); Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: info what(Context& /*context*/) const Chris@16: { Chris@16: return info(qi::detail::what::is()); Chris@16: } Chris@16: Chris@16: V n; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Parser generators: make_xxx function (objects) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct make_binary_parser Chris@16: { Chris@16: typedef any_binary_parser result_type; Chris@16: result_type operator()(unused_type, unused_type) const Chris@16: { Chris@16: return result_type(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct make_binary_lit_parser Chris@16: { Chris@16: typedef binary_lit_parser result_type; Chris@16: template Chris@16: result_type operator()(Terminal const& term, unused_type) const Chris@16: { Chris@16: return result_type(fusion::at_c<0>(term.args)); Chris@16: } Chris@16: }; Chris@16: Chris@16: #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \ Chris@16: template \ Chris@16: struct make_primitive \ Chris@16: : make_binary_parser, \ Chris@16: boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct make_primitive< \ Chris@16: terminal_ex > , Modifiers> \ Chris@16: : make_binary_lit_parser, \ Chris@16: boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32) Chris@16: #ifdef BOOST_HAS_LONG_LONG Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64) Chris@16: #endif Chris@16: Chris@16: #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE Chris@16: Chris@16: #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \ Chris@16: template \ Chris@16: struct make_primitive \ Chris@16: : make_binary_parser, \ Chris@16: boost::endian::endianness::endiantype, bits> {}; \ Chris@16: \ Chris@16: template \ Chris@16: struct make_primitive< \ Chris@16: terminal_ex >, Modifiers> \ Chris@16: : make_binary_lit_parser, \ Chris@16: boost::endian::endianness::endiantype, \ Chris@16: bits> {}; \ Chris@16: \ Chris@16: /***/ Chris@16: Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64) Chris@16: BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64) Chris@16: Chris@16: #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE Chris@16: Chris@16: }}} Chris@16: Chris@16: #endif