binary.hpp 16 KB

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