diff options
Diffstat (limited to 'src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp')
-rw-r--r-- | src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp new file mode 100644 index 00000000..93453bac --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp @@ -0,0 +1,304 @@ +/*============================================================================= + 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; +} + |