summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp')
-rw-r--r--src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp304
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;
+}
+