fork download
  1. #include <sstream>
  2. #include <istream>
  3. #include <iostream>
  4.  
  5. void fill_testdata(std::ostream& os);
  6.  
  7. struct FormatData {
  8. std::string signature, header; // e.g. 4 + 16 = 20 bytes - could be different, of course
  9. std::string payload; // 16bit length prefixed
  10. };
  11.  
  12. FormatData parse(std::istream& is);
  13.  
  14. int main() {
  15. std::stringstream ss;
  16. fill_testdata(ss);
  17.  
  18. try {
  19. FormatData data = parse(ss);
  20.  
  21. std::cout << "actual payload bytes: " << data.payload.length() << "\n";
  22. std::cout << "payload: '" << data.payload << "'\n";
  23. } catch(std::runtime_error const& e) {
  24. std::cout << "Error: " << e.what() << "\n";
  25. }
  26. }
  27.  
  28. // some testdata
  29. void fill_testdata(std::ostream& os)
  30. {
  31. char data[] = {
  32. 'S' , 'I' , 'G' , 'N' , '\x00' , // 0..4
  33. '\x00', '\x00', '\x00', '\x00', '\x00' , // 5..9
  34. '\x00', '\x00', '\x00', '\x00', '\x00' , // 10..14
  35. '\x00', '\x00', '\x00', '\x00', '\x00' , // 15..19
  36. '\x0b', '\x00', 'H' , 'e' , 'l' , // 20..24
  37. 'l' , 'o' , ' ' , 'w' , 'o' , // 25..29
  38. 'r' , 'l' , 'd' , '!' , // 30..33
  39. };
  40. os.write(data, sizeof(data));
  41. }
  42.  
  43. //#define BOOST_SPIRIT_DEBUG
  44. #include <boost/fusion/adapted/struct.hpp>
  45. #include <boost/spirit/include/qi.hpp>
  46. #include <boost/spirit/include/phoenix.hpp>
  47. namespace qi = boost::spirit::qi;
  48.  
  49. BOOST_FUSION_ADAPT_STRUCT(FormatData, signature, header, payload)
  50.  
  51. template <typename It>
  52. struct FileFormat : qi::grammar<It, FormatData()> {
  53. FileFormat() : FileFormat::base_type(start) {
  54. using namespace qi;
  55.  
  56. signature = string("SIGN"); // 4 byte signature, just for example
  57. header = repeat(16) [byte_]; // 16 byte header, same
  58.  
  59. payload %= omit[little_word[_len=_1]] >> repeat(_len) [byte_];
  60. start = signature >> header >> payload;
  61.  
  62. //BOOST_SPIRIT_DEBUG_NODES((start)(signature)(header)(payload))
  63. }
  64. private:
  65. qi::rule<It, FormatData()> start;
  66. qi::rule<It, std::string()> signature, header;
  67.  
  68. qi::_a_type _len;
  69. qi::rule<It, std::string(), qi::locals<uint16_t> > payload;
  70. };
  71.  
  72. FormatData parse(std::istream& is) {
  73. using it = boost::spirit::istream_iterator;
  74.  
  75. FormatData data;
  76. it f(is >> std::noskipws), l;
  77. bool ok = parse(f, l, FileFormat<it>{}, data);
  78.  
  79. if (!ok)
  80. throw std::runtime_error("parse failure\n");
  81.  
  82. return data;
  83. }
  84.  
Success #stdin #stdout 0s 15272KB
stdin
Standard input is empty
stdout
actual payload bytes: 11
payload: 'Hello world'