binary.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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::endian::order) bits>
  181. struct what;
  182. template <>
  183. struct what<boost::endian::order::little>
  184. {
  185. static char const* is()
  186. {
  187. return "little-endian binary";
  188. }
  189. };
  190. template <>
  191. struct what<boost::endian::order::big>
  192. {
  193. static char const* is()
  194. {
  195. return "big-endian binary";
  196. }
  197. };
  198. }
  199. ///////////////////////////////////////////////////////////////////////////
  200. template <typename T, BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits>
  201. struct any_binary_parser : primitive_parser<any_binary_parser<T, endian, bits> >
  202. {
  203. template <typename Context, typename Iterator>
  204. struct attribute
  205. {
  206. typedef boost::endian::endian_arithmetic<endian, typename T::type,
  207. bits> type;
  208. };
  209. template <typename Iterator, typename Context
  210. , typename Skipper, typename Attribute>
  211. bool parse(Iterator& first, Iterator const& last
  212. , Context& /*context*/, Skipper const& skipper
  213. , Attribute& attr_param) const
  214. {
  215. qi::skip_over(first, last, skipper);
  216. typename attribute<Context, Iterator>::type attr_;
  217. unsigned char* bytes = attr_.data();
  218. Iterator it = first;
  219. for (unsigned int i = 0; i < sizeof(attr_); ++i)
  220. {
  221. if (it == last)
  222. return false;
  223. *bytes++ = *it++;
  224. }
  225. first = it;
  226. spirit::traits::assign_to(attr_, attr_param);
  227. return true;
  228. }
  229. template <typename Context>
  230. info what(Context& /*context*/) const
  231. {
  232. return info(qi::detail::what<endian>::is());
  233. }
  234. };
  235. ///////////////////////////////////////////////////////////////////////////
  236. template <typename V, typename T
  237. , BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits>
  238. struct binary_lit_parser
  239. : primitive_parser<binary_lit_parser<V, T, endian, bits> >
  240. {
  241. template <typename Context, typename Iterator>
  242. struct attribute
  243. {
  244. typedef unused_type type;
  245. };
  246. binary_lit_parser(V n_)
  247. : n(n_) {}
  248. template <typename Iterator, typename Context
  249. , typename Skipper, typename Attribute>
  250. bool parse(Iterator& first, Iterator const& last
  251. , Context& /*context*/, Skipper const& skipper
  252. , Attribute& attr_param) const
  253. {
  254. qi::skip_over(first, last, skipper);
  255. boost::endian::endian_arithmetic<endian, typename T::type, bits> attr_;
  256. #if defined(BOOST_MSVC)
  257. // warning C4244: 'argument' : conversion from 'const int' to 'foo', possible loss of data
  258. #pragma warning(push)
  259. #pragma warning(disable: 4244)
  260. #endif
  261. attr_ = n;
  262. #if defined(BOOST_MSVC)
  263. #pragma warning(pop)
  264. #endif
  265. unsigned char* bytes = attr_.data();
  266. Iterator it = first;
  267. for (unsigned int i = 0; i < sizeof(attr_); ++i)
  268. {
  269. if (it == last || *bytes++ != static_cast<unsigned char>(*it++))
  270. return false;
  271. }
  272. first = it;
  273. spirit::traits::assign_to(attr_, attr_param);
  274. return true;
  275. }
  276. template <typename Context>
  277. info what(Context& /*context*/) const
  278. {
  279. return info(qi::detail::what<endian>::is());
  280. }
  281. V n;
  282. };
  283. ///////////////////////////////////////////////////////////////////////////
  284. // Parser generators: make_xxx function (objects)
  285. ///////////////////////////////////////////////////////////////////////////
  286. template <typename T, BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits>
  287. struct make_binary_parser
  288. {
  289. typedef any_binary_parser<T, endian, bits> result_type;
  290. result_type operator()(unused_type, unused_type) const
  291. {
  292. return result_type();
  293. }
  294. };
  295. template <typename V, typename T
  296. , BOOST_SCOPED_ENUM(boost::endian::order) endian, int bits>
  297. struct make_binary_lit_parser
  298. {
  299. typedef binary_lit_parser<V, T, endian, bits> result_type;
  300. template <typename Terminal>
  301. result_type operator()(Terminal const& term, unused_type) const
  302. {
  303. return result_type(fusion::at_c<0>(term.args));
  304. }
  305. };
  306. #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endiantype, bits) \
  307. template <typename Modifiers> \
  308. struct make_primitive<tag::name, Modifiers> \
  309. : make_binary_parser<detail::integer<bits>, \
  310. boost::endian::order::endiantype, bits> {}; \
  311. \
  312. template <typename Modifiers, typename A0> \
  313. struct make_primitive< \
  314. terminal_ex<tag::name, fusion::vector1<A0> > , Modifiers> \
  315. : make_binary_lit_parser<A0, detail::integer<bits>, \
  316. boost::endian::order::endiantype, bits> {}; \
  317. \
  318. /***/
  319. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(byte_, native, 8)
  320. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(word, native, 16)
  321. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_word, big, 16)
  322. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_word, little, 16)
  323. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(dword, native, 32)
  324. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_dword, big, 32)
  325. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_dword, little, 32)
  326. #ifdef BOOST_HAS_LONG_LONG
  327. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(qword, native, 64)
  328. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_qword, big, 64)
  329. BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_qword, little, 64)
  330. #endif
  331. #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE
  332. #define BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(name, endiantype, bits) \
  333. template<typename Modifiers> \
  334. struct make_primitive<tag::name, Modifiers> \
  335. : make_binary_parser<detail::floating_point<bits>, \
  336. boost::endian::order::endiantype, bits> {}; \
  337. \
  338. template<typename Modifiers, typename A0> \
  339. struct make_primitive< \
  340. terminal_ex<tag::name, fusion::vector1<A0> >, Modifiers> \
  341. : make_binary_lit_parser<A0, detail::floating_point<bits>, \
  342. boost::endian::order::endiantype, \
  343. bits> {}; \
  344. \
  345. /***/
  346. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_float, native, 32)
  347. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_float, big, 32)
  348. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_float, little, 32)
  349. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(bin_double, native, 64)
  350. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(big_bin_double, big, 64)
  351. BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE(little_bin_double, little, 64)
  352. #undef BOOST_SPIRIT_MAKE_BINARY_IEEE754_PRIMITIVE
  353. }}}
  354. #endif