123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*=============================================================================
- Copyright (c) 2002-2003 Joel de Guzman
- http://spirit.sourceforge.net/
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- #include <boost/spirit/include/classic_core.hpp>
- #include <boost/spirit/include/classic_push_back_actor.hpp>
- #include <boost/spirit/include/classic_if.hpp>
- #include <boost/spirit/include/classic_for.hpp>
- #include <boost/spirit/include/phoenix1.hpp>
- #include <iostream>
- #include <string>
- #include <vector>
- #include <algorithm>
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Sample parser for binary data. This sample highlights the use of dynamic
- // parsing where the result of actions direct the actual parsing behavior.
- // We shall demonstrate 1) the use of phoenix to implement lambda (unnamed)
- // functions, 2) dynamic looping using for_p, 3) the push_back_a actor for
- // stuffing data into a vector, and 4) the if_p parser for choosing parser
- // branches based on semantic conditions.
- //
- // << Sample idea by Florian Weimer >>
- //
- // For simplicity, we shall use bytes as atoms (and not 16-bit quantities
- // in big-endian format or something similar, which would be more realistic)
- // and PASCAL strings.
- //
- // A packet is the literal octet with value 255, followed by a variable
- // octet N (denoting the total length of the packet), followed by N-2 octets
- // (the payload). The payload contains a variable-length header, followed
- // by zero or more elements.
- //
- // The header contains a single PASCAL string.
- //
- // An element is a PASCAL string (alternative: an element is an octet M,
- // followed by [M/8] bytes, i.e. the necessary number of bytes to store M
- // bits).
- //
- // (This data structure is inspired by the format of a BGP UPDATE message.)
- //
- // Packet layout:
- //
- // .-------------------.
- // | 0xff | ^
- // +-------------------+ |
- // | packet length | |
- // +-------------------+ | number of bytes indicated by packet length
- // : : |
- // : payload : |
- // | | v
- // `-------------------'
- //
- // Payload layout:
- //
- // .-------------------.
- // | header length |
- // +-------------------+
- // | header octets | ^
- // : : | number of octets given by header length
- // : : |
- // : : v
- // +-------------------+
- // | IPv4 prefix | ^
- // : : | IPv4 prefixes have variable length (see
- // +-------------------+ | below). The number of prefixes is
- // | IPv4 prefix | | determined by the packet length.
- // : : |
- // +-------------------+ |
- // : : |
- // : : v
- //
- //
- // IPv4 prefix layout comes in five variants, depending on the first
- // octet:
- //
- // .-------------------.
- // | 0x00 | single octet, corresponds to 0.0.0.0/0
- // `-------------------'
- //
- // .-------------------.
- // | 0x01 to 0x08 | two octets, prefix lengths up to /8.
- // +-------------------+
- // | MSB of network |
- // `-------------------'
- //
- // .-------------------.
- // | 0x09 to 0x10 | three octets, prefix lengths up to /16.
- // +-------------------+
- // | MSB of network |
- // +-------------------+
- // | next octet |
- // `-------------------'
- //
- // .-------------------.
- // | 0x11 to 0x18 | four octets, prefix lengths up to /24.
- // +-------------------+
- // | MSB of network |
- // +-------------------+
- // | next octet |
- // +-------------------+
- // | next octet |
- // `-------------------'
- //
- // .-------------------.
- // | 0x19 to 0x20 | five octets, prefix lengths up to /32.
- // +-------------------+
- // | MSB of network |
- // +-------------------+
- // | next octet |
- // +-------------------+
- // | next octet |
- // +-------------------+
- // | LSB of network |
- // `-------------------'
- //
- ///////////////////////////////////////////////////////////////////////////////
- using namespace std;
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- using namespace phoenix;
- struct ipv4_prefix_data
- {
- char prefix_len, n0, n1, n2, n3;
- ipv4_prefix_data()
- : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {}
- };
- struct ipv4_data
- {
- char packet_len, header_len;
- std::string header;
- std::vector<ipv4_prefix_data> prefixes;
- ipv4_data()
- : packet_len(0),header_len(0){}
- };
- struct ipv4 : public grammar<ipv4>
- {
- template <typename ScannerT>
- struct definition
- {
- definition(ipv4 const& self)
- {
- packet =
- '\xff'
- >> anychar_p[var(self.data.packet_len) = arg1]
- >> payload
- ;
- payload =
- anychar_p[var(self.data.header_len) = arg1]
- >> for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i))
- [
- anychar_p[var(self.data.header) += arg1]
- ]
- >> *ipv4_prefix
- ;
- ipv4_prefix =
- anychar_p
- [
- var(temp.prefix_len) = arg1,
- var(temp.n0) = 0,
- var(temp.n1) = 0,
- var(temp.n2) = 0,
- var(temp.n3) = 0
- ]
- >> if_p(var(temp.prefix_len) > 0x00)
- [
- anychar_p[var(temp.n0) = arg1]
- >> if_p(var(temp.prefix_len) > 0x08)
- [
- anychar_p[var(temp.n1) = arg1]
- >> if_p(var(temp.prefix_len) > 0x10)
- [
- anychar_p[var(temp.n2) = arg1]
- >> if_p(var(temp.prefix_len) > 0x18)
- [
- anychar_p[var(temp.n3) = arg1]
- ]
- ]
- ]
- ]
- [
- push_back_a(self.data.prefixes, temp)
- ]
- ;
- }
- int i;
- ipv4_prefix_data temp;
- rule<ScannerT> packet, payload, ipv4_prefix;
- rule<ScannerT> const&
- start() const { return packet; }
- };
- ipv4(ipv4_data& data)
- : data(data) {}
- ipv4_data& data;
- };
- ////////////////////////////////////////////////////////////////////////////
- //
- // Main program
- //
- ////////////////////////////////////////////////////////////////////////////
- int
- as_byte(char n)
- {
- if (n < 0)
- return n + 256;
- return n;
- }
- void
- print_prefix(ipv4_prefix_data const& prefix)
- {
- cout << "prefix length = " << as_byte(prefix.prefix_len) << endl;
- cout << "n0 = " << as_byte(prefix.n0) << endl;
- cout << "n1 = " << as_byte(prefix.n1) << endl;
- cout << "n2 = " << as_byte(prefix.n2) << endl;
- cout << "n3 = " << as_byte(prefix.n3) << endl;
- }
- void
- parse_ipv4(char const* str, unsigned len)
- {
- ipv4_data data;
- ipv4 g(data);
- parse_info<> info = parse(str, str+len, g);
- if (info.full)
- {
- cout << "-------------------------\n";
- cout << "Parsing succeeded\n";
- cout << "packet length = " << as_byte(data.packet_len) << endl;
- cout << "header length = " << as_byte(data.header_len) << endl;
- cout << "header = " << data.header << endl;
- for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix);
- cout << "-------------------------\n";
- }
- else
- {
- cout << "Parsing failed\n";
- cout << "stopped at:";
- for (char const* s = info.stop; s != str+len; ++s)
- cout << static_cast<int>(*s) << endl;
- }
- }
- // Test inputs:
- // The string in the header is "empty", the prefix list is empty.
- char const i1[8] =
- {
- 0xff,0x08,0x05,
- 'e','m','p','t','y'
- };
- // The string in the header is "default route", the prefix list
- // has just one element, 0.0.0.0/0.
- char const i2[17] =
- {
- 0xff,0x11,0x0d,
- 'd','e','f','a','u','l','t',' ',
- 'r','o','u','t','e',
- 0x00
- };
- // The string in the header is "private address space", the prefix list
- // has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
- char const i3[32] =
- {
- 0xff,0x20,0x15,
- 'p','r','i','v','a','t','e',' ',
- 'a','d','d','r','e','s','s',' ',
- 's','p','a','c','e',
- 0x08,0x0a,
- 0x0c,0xac,0x10,
- 0x10,0xc0,0xa8
- };
- int
- main()
- {
- parse_ipv4(i1, sizeof(i1));
- parse_ipv4(i2, sizeof(i2));
- parse_ipv4(i3, sizeof(i3));
- return 0;
- }
|