-// Copyright (C) 2007
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.be>
//
// This program is free software; you can redistribute it and/or modify
Here \c someField(), \c someOtherField() and \c someVector() are accessor methods named after
the field name. Each returns a parser object. Simple parsers can be used like their
- corresponding basic type (e.g. a Parse_UInt16 field can be used like an unsigned integer), more
+ corresponding basic type (e.g. a UInt16Parser field can be used like an unsigned integer), more
complex parsers provide type specific access members. Assigning a value to a parser will change
the underlying representation (the packet data).
Parsers can be grouped into several categories. These categories are not all defined rigorously
but are nevertheless helpful when working with the parsers:
- \li <em>\ref parserimpl_value</em> provide the lowest level parsers (e.g. senf::Parse_UInt16 which
+ \li <em>\ref parserimpl_value</em> provide the lowest level parsers (e.g. senf::UInt16Parser which
returns an integer value).
\li <em>\ref parserimpl_collection</em> are parsers which model a collection of sub-elements like
- senf::Parse_List or senf::Parse_Vector.
+ senf::ListParser or senf::VectorParser.
\li <em>\ref parserimpl_composite</em> collect several fields of arbitrary type into a new
parser. Parsers defined using the \ref packetparsermacros fall under this category.
\li <em>\ref parserimpl_packet</em> are used to define a packet type.
\warning Parsers are like iterators: They are invalidated <em>whenever the size of the packet's
data is changed</em>. You should not store a parser anywhere. If you want to keep a parser
- reference, use the senf::SafePacketParser wrapper. You still will need to take extra care to
+ reference, use the senf::SafePacketParserWrapper wrapper. You still will need to take extra care to
ensure the parser is not invalidated.
\section parserimpl Packet parser categories
pointers, it should hold a copy of the value (it's Ok for \c value() to return such a reference
as long as assigning it to a \c value_type variable will copy the value).
+ \see parseint
+
\subsection parserimpl_collection Collection parsers
A collection parser \a SomeParser should model STL containers. The parsers themselves will
\endcode
You will probably only very seldom need to implement a completely new collection
- parser. Instead, you can rely on senf::Parse_Vector or senf::Parse_List and implement new
+ parser. Instead, you can rely on senf::VectorParser or senf::ListParser and implement new
policies.
+ \see parsecollection
+
\subsection parserimpl_composite Composite parsers
If possible, composite parsers should be implemented using the \ref packetparsermacros. In
parsers). When defining composite parsers without the help of the \ref packetparsermacros, you
should provide those same members.
- \subsection parserimpl_packet Packet parsers
+ \subsection parserimpl_packet Protocol parsers
- Packet parsers are composite parsers with relaxed requirements. Since a packet parser will never
- be used as a sub-parser (it will not be used within another composite parser or as value type in
- a collection parser), the value returned by senf::bytes for this parser must not necessarily
- cover the complete packet (e.g. if the packet has a trailer, the trailer will live outside the
- range given by senf::bytes). You may define any member you want to have in your packets field
- interface. These members may access the packet data in any way. You just need to ensure, that
- the integration into the packet-type is correct (the senf::PacketTypeMixin will by default use
- senf::bytes() to find the end of the header).
+ Protocol parsers are composite parsers with relaxed requirements. Since a Protocol parser will
+ never be used as a sub-parser (it will not be used within another composite parser or as value
+ type in a collection parser), the value returned by senf::bytes for this parser must not
+ necessarily cover the complete packet (e.g. if the packet has a trailer, the trailer will live
+ outside the range given by senf::bytes). You may define any member you want to have in your
+ packets field interface. These members may access the packet data in any way. You just need to
+ ensure, that the integration into the packet-type is correct (the senf::PacketTypeMixin will by
+ default use senf::bytes() to find the end of the header).
<hr>
*/
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/optional.hpp>
-#include "../Utils/SafeBool.hh"
+#include "../Utils/safe_bool.hh"
#include "PacketTypes.hh"
#include "PacketData.hh"
#include "ParseHelpers.hh"
Both kinds of parser need to derive from PacketParserBase and implement several required
members. Which members to implement depends on the parsers flavor. There are two ways how to
do this.
- \li If the parser just consists of a simple sequence of consecutive fields (sub-parsers),
- the \ref SENF_PACKET_PARSER_DEFINE_FIELDS and \ref
- SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros provide a simple and convenient way to
- define the packet
+ \li If the parser just consists of sequence of consecutive fields (sub-parsers), the \ref
+ packetparsermacros provide a simple yet flexible way to define a packet parser.
\li In more complex cases, you need to implement the necessary members manually.
This documentation is about the manual implementation. You should nevertheless read through
// used to construct the sub-parsers. This member either takes an iterator to the
// data to be parsed or just an offset in bytes.
- senf::Parse_UInt16 type() const { return parse<Parse_UInt16>( 0 ); }
- senf::Parse_UInt16 size() const { return parse<Parse_UInt16>( 2 ); }
+ senf::UInt16Parser type() const { return parse<UInt16Parser>( 0 ); }
+ senf::UInt16Parser size() const { return parse<UInt16Parser>( 2 ); }
};
\endcode
here. The size of the interpreted is given by
<tt>senf::bytes(</tt><em>parser
instance</em><tt>)</tt>. */
+
+ data_iterator i(size_type offset) const; ///< Return iterator \a offset bytes from the start
+ /**< The return value is the same as i() + \a
+ offset. However, the parser checks, that the iterator is
+ still within range of the raw data
+ container. Otherwise a TruncatedPacketException is
+ thrown.
+
+ \throws TruncatedPacketException if the raw data
+ container does not hold at least \a offset bytes
+ starting at i(). */
+
state_type state() const; ///< Return state of this parser
/**< The value returned should be interpreted as an opaque
value provided just to be forwarded to other
parsers. */
+
PacketData & data() const; ///< Access the packets raw data container
/**< This member will return the raw data container holding
the data which is parsed by \c this parser. */
/**< This is the constructor used by most parsers. The
parameters are just forwarded from the derived classes
constructor parameters. */
+
PacketParserBase(data_iterator i, state_type s, size_type size);
///< Size checking constructor
/**< In addition to the standard constructor, this
bool check(size_type size) const; ///< Check size of data container
/**< \returns \c true, if the data container holds at least
\a size beginning at i(), \c false otherwise. */
+
void validate(size_type size) const; ///< Validate size of data container
/**< \throws TruncatedPacketException if the raw data
container does not hold at least \a size bytes
/**< Creates a new instance of \a Parser to parse data
beginning at \a i. Automatically passes \a state() to
the new parser. */
+
+ template <class Parser, class Arg> Parser parse(Arg const & arg, data_iterator i) const;
+ ///< Create sub-parser
+ /**< This is like parse(data_iterator), however it passes
+ the extra argument \a arg to the \a Parser
+ constructor. */
+
template <class Parser> Parser parse(size_type n) const; ///< Create sub-parser
/**< Creates a new instance of \a Parser to parse data
* beginning at i()<tt> + </tt>\a n. Automatically passes \a
state() to the new parser. */
+ template <class Parser, class Arg> Parser parse(Arg const & arg, size_type n) const;
+ ///< Create sub-parser
+ /**< This is like parse(size_type), however it passes the
+ extra argument \a arg to the \a Parser constructor. */
+
void defaultInit() const; ///< Default implementation
/**< This is just an empty default
implementation. Re-implement this member in your own
parsers if needed. */
Packet packet() const; ///< Get packet this parser is parsing from
- /**< \important This member should only be used from packet
+ /**< \note This member should only be used from packet
parsers when access to previous or following packets is
needed e.g. for calculating checksums etc. */
data_iterator i_;
PacketData * data_;
- template <class Parser> friend class SafePacketParser;
+ template <class Parser> friend class SafePacketParserWrapper;
};
/** \brief Return raw size parsed by the given parser object
PacketParserBase::size_type bytes(Parser p);
namespace detail { template <class Parser> class ParserInitBytes; }
+ namespace detail { template <class Parser> class ParserIsFixed; }
/** \brief Return number of bytes to allocate to new object of given type
struct init_bytes : public detail::ParserInitBytes<Parser>
{};
+ /** \brief Test, whether a parser is a fixed-size parser
+
+ This meta-function is called like
+ \code
+ senf::is_fixed<SomeParser>::value
+ \endcode
+
+ This expression evaluates to a compile-time constant boolean expression which is \c true, if
+ \a SomeParser is a fixed size parser, \c false otherwise
+
+ \param[in] Parser The Parser to test
+ \returns \c true, if \a Parser is fixed size, \c false otherwise
+ \ingroup packetparser
+ */
+ template <class Parser>
+ struct is_fixed : public detail::ParserIsFixed<Parser>
+ {};
+
# ifndef DOXYGEN
template <class Parser>
typename boost::enable_if<
SENF_PARSER_FINALIZE(VoidPacketParser);
};
- /** \brief Iterator re-validating Parser wrapper
-
- An ordinary parser will be invalidated whenever the raw data container's size is
- changed. This can complicate some algorithms considerably.
-
- This wrapper will update the parsers iterator (the value returned by the i() member) on
- every access. This ensures that the iterator will stay valid.
-
- \attention Beware however, if you insert or remove data before the safe wrapper, the
- location will \e not be updated accordingly and therefore the parser will be
- invalid.
-
- Additionally a SafePacketParser has an uninitialized state. The only allowed operations in
- this state are the boolean test for validity and assigning another parser.
-
- \ingroup packetparser
- */
- template <class Parser>
- class SafePacketParser
- : public SafeBool< SafePacketParser<Parser> >
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- ///////////////////////////////////////////////////////////////////////////
- ///\name Structors and default members
- ///@{
-
- // default copy constructor
- // default copy assignment
- // default destructor
- SafePacketParser(); ///< Create an empty uninitialized SafePacketParser
-
- // conversion constructors
- SafePacketParser(Parser parser); ///< Initialize SafePacketParser from \a parser
-
- SafePacketParser & operator=(Parser parser); ///< Assign \a parser to \c this
-
- ///@}
- ///////////////////////////////////////////////////////////////////////////
-
- Parser operator*() const; ///< Access the stored parser
- /**< On every access, the stored parsers iterator will be
- updated / re-validated. */
- Parser const * operator->() const; ///< Access the stored parser
- /**< On every access, the stored parsers iterator will be
- updated / re-validated. */
- bool boolean_test() const; ///< Check validity
-
- protected:
-
- private:
- mutable boost::optional<Parser> parser_;
- senf::safe_data_iterator i_;
- };
-
}
///////////////////////////////hh.e////////////////////////////////////////