Helper macros for defining new packet parsers
[The PacketParser facility]


Detailed Description

To simplify the definition of simple packet parsers, several macros are provided. Before using these macros you should familiarize yourself with the packet parser interface as described in senf::PacketParserBase.

These macros simplify providing the above defined interface. A typical packet declaration using these macros has the following form (This is a concrete example from the definition of the ethernet packet in DefaultBundle/EthernetPacket.hh)

struct EthVLanPacketParser : public PacketParserBase
{
#   include SENF_FIXED_PARSER()

    SENF_PARSER_BITFIELD( priority,  3, unsigned );
    SENF_PARSER_BITFIELD( cfi,       1, bool     );
    SENF_PARSER_BITFIELD( vlanId,   12, unsigned );

    SENF_PARSER_FIELD( type, UInt16Parser );

    SENF_PARSER_FINALIZE(EthVLanPacketParser);
};

The macros take care of the following:

  • They define the accessor functions returning parsers of the given type.
  • They automatically calculate the offset of the fields from the preceding fields.
  • The macros provide a definition for init()
  • The macros define the bytes(), fixed_bytes and init_bytes members as needed.
You may define either a fixed or a dynamically sized parser. Fixed size parsers are defined by starting the packet with #include SENF_FIXED_PARSER(), dynamically sized parsers start with #include SENF_PARSER(). The different members are implemented such that:
  • The needed parser constructor is defined
  • init() calls defaultInit(). defaultInit() is defined to call init() on each of the fields.
  • bytes() (on dynamically sized parser) respectively fixed_bytes (on fixed size parsers) is defined to return the sum of the sizes of all fields.
  • On dynamically sized parsers, init_bytes is defined to return the sum of the init_byte's of all fields

The Parser Macro micro-language

The macros provided to help implement composite parsers implement a very small declarative language. This way of to think of the macros simplifies understanding, how the macros work.

Central to this language is the concept of current offset. The current offset is the place (in bytes) from the beginning of the parser at which the next field will be added. Adding fields to the parser will advance this offset by the size of the field added. Additional commands allow to arbitrarily manipulate the current offset manually.

For fixed size parsers, the current offset is a single constant integral value, the number of bytes from the parsers start. For dynamically sized parsers, the current offset really consists of two values: One is the number of bytes from the parsers start, which however needs not be a constant expression, the other value is the init_bytes value at this point, which is an integral constant.

To demonstrate this functionality, here a more complex example (taken from MPEGDVBBundle and then simplified by removing some fields)

struct Parse_DSMCCSection : public PacketParserBase
{
#   include SENF_FIXED_PARSER()

    SENF_PARSER_FIELD    ( table_id            , UInt8Parser   );

    SENF_PARSER_BITFIELD ( ssi                 ,  1 , bool     );
    SENF_PARSER_BITFIELD ( private_indicator   ,  1 , bool     );
    SENF_PARSER_SKIP_BITS( 2 );
    SENF_PARSER_BITFIELD ( sec_length          , 12 , unsigned );

    SENF_PARSER_FIELD    ( table_id_extension  , UInt16Parser  );

    SENF_PARSER_FINALIZE( Parse_DSMCCSection );
};

struct Parse_DatagramSection : public Parse_DSMCCSection
{
#   include SENF_FIXED_PARSER()

    SENF_PARSER_INHERIT( Parse_DSMCCSection );

    SENF_PARSER_FIELD    ( mac_addr_4          , UInt8Parser   );
    SENF_PARSER_FIELD    ( mac_addr_3          , UInt8Parser   );

    SENF_PARSER_FINALIZE( Parse_DatagramSection );

    // Parse table_id_extension as two bytes
    SENF_PARSER_GOTO( table_id_extension );
    SENF_PARSER_FIELD    ( mac_addr_6          , UInt8Parser   );
    SENF_PARSER_FIELD    ( mac_addr_5          , UInt8Parser   );
};

This code defines two parsers, the second of which is based on the first. Both are fixed size parsers. The definition of Parse_DSMCCSection is straight forward (more on bit fields below).

The derived parser is a little bit more complex. It starts out the same defining itself as a fixed size parser. Then the base class is imported. Among other things, this call sets the current offset to the first byte after the base parser (the base parser need not be implemented using the packet parser macros, it just needs to be a valid parser). The additional fields mac_addr_4 and mac_addr_3 are defined. Then we finalize the parser declaration.

After SENF_PARSER_FINALIZE we add two more fields but not at the end of the parser. SENF_PARSER_GOTO jumps back to a previously defined label or field. Since the base parser Parse_DSMCCSection is defined using the packet parser macros, we can even jump to labels or fields defined in the base parser. Here, we jump to the beginning of the table_id_extension field. mac_addr_6 and mac_addr_5 are therefore defined starting at that offset and therefore overlay the table_id_extension field.

Parser initialization

SENF_FIXED_PARSER(), SENF_PARSER(), SENF_PARSER_INHERIT(), SENF_PARSER_INIT(), SENF_PARSER_FINALIZE()
Every parser using the parser macros starts either with #include SENF_PARSER() or with #include SENF_FIXED_PARSER(). This command sets the current offset to zero and defines the type of parser to define.

A following optional SENF_PARSER_INHERIT(base_class) is necessary if the parser does not derive from senf::PacketParserBase. This call sets the base class and advances the current offset to the end of the base parser.

SENF_PARSER_INIT() is used to define the parser initialization code (the init() member).

SENF_PARSER_FINALIZE(class_name) is called to define the parsers constructor, the init() member and to set the parsers size (fixed_bytes for fixed size parsers or bytes() and init_bytes for dynamically sized parsers). It is valid to define further fields after SENF_PARSER_FINALIZE() has been called, however

  • Fields defined after SENF_PARSER_FINALIZE() will not be initialized by defaultInit() (and therefore not by the default provided init() member). This can be very helpful when defining overlaying fields to avoid initializing some bytes multiple times.
  • The size of the parser is given by the current offset at the time of the SENF_PARSER_FINALIZE() call.

Defining fields

SENF_PARSER_FIELD(), SENF_PARSER_FIELD_RO(), SENF_PARSER_PRIVATE_FIELD(), SENF_PARSER_CUSTOM_FIELD()
There are quite a few commands available to define fields. All these macros do the same thing: they define a field accessor plus some auxiliary symbols. The accessor will use the parser type passed to the macro to parse the field. The current offset is adjusted according to the size of that parser. Normally, the parser will return an instance of the given parser type.

There are some properties the field defining macros might have. These properties are parts of the macro name:

RO: Read only fields
Macros with RO in their name define read only fields. This is only possible, if the field's parser is a value parser (that is, it must have a value_type typedef member and must provide the value() accessor member function). In this case, the value returned from the name() accessor member is not the parser but the parsers value and therefore it does not allow assignment to the field.
PRIVATE: Fields private to the parser class
A private field will not be accessible from the outside (it is made private to the parser class). This is very handy when providing other accessor members to access a field in a manner more suitable for the specific field, when combining several fields into a single return value etc.
The field defining macros come in groups which members only differ in their properties:
Standard fields:
SENF_PARSER_FIELD(), SENF_PARSER_FIELD_RO(), SENF_PARSER_PRIVATE_FIELD() define standard fields.
Arbitrary custom field:
SENF_PARSER_CUSTOM_FIELD()

See the documentation of each of these macros for a detailed description of the macro arguments and usage. Bit-fields are handled in the following section.

There also some supplementary macros for defining fields of more complex composite types (e.g. vectors). See the list of 'Defines' further down this page.

Bit-fields

SENF_PARSER_BITFIELD(), SENF_PARSER_BITFIELD_RO(), SENF_PARSER_PRIVATE_BITFIELD()
Bit-fields play a special role. They are quite frequent in packet definitions but don't fit into the byte offset based parsing infrastructure defined so far. Since defining the correctly parameterized senf::IntFieldParser, senf::UIntFieldParser and senf::FlagParser typedefs is quite tedious, these helper macros are provided.

It is important to recognize, that the current offset does not include the current bit position. The current offset after defining a bit-field will be the first complete byte after that bit-field. Only the bit-field macros additionally take care of the current bit position which is reset automatically by any intervening non-bitfield command.

So bit-field commands will come in groups. Any group of consecutive bitfield commands defines a set of consecutive bits. The group as a whole will always be considered to cover a fixed number of complete bytes. If the group does not cover those bytes completely (there are some bit's left at the end), those bit's will be skipped.

Since consecutive bit-field commands are aggregated into a single bit-field group, the offset of all these bit-fields will be the offset of the beginning of the group irrespective of the number of bits parsed so far. Changing the offset to some bitfield using SENF_PARSER_GOTO() will therefore always go to the position at the beginning of this bitfield group. And since the current offset does not include the bit position, the bit position will be 0, the first bit. You may however break a bit-field group into two groups (at a byte boundary) by placing a SENF_PARSER_LABEL() command between the two groups.

The additional command SENF_PARSER_SKIP_BITS() can be used to skip bit's between two bit-fields.

Manipulating the current offset

SENF_PARSER_SKIP(), SENF_PARSER_SKIP_BITS(), SENF_PARSER_GOTO(), SENF_PARSER_GOTO_OFFSET(), SENF_PARSER_LABEL()
To define more complex parsers, there are some macro commands which change the current offset.

SENF_PARSER_SKIP(bytes) will skip the given number of bytes. SENF_PARSER_SKIP_BITS(bits) will work within bitfield definition to skip that number of bits.

SENF_PARSER_GOTO(label_or_field) will change the offset to the given field or label. The following fields will therefore start at that offset and overlay any fields already defined.

SENF_PARSER_GOTO_OFFSET(offset) will jump to the given byte offset from the start of the parser.

SENF_PARSER_LABEL(name) will define name as a label for the current offset which can then later be referenced using SENF_PARSER_GOTO(). This also defines name_offset as a constant or member (for fixed respectively dynamically sized parsers).

It is very important to recognize, that the size of the parser is defined by the current offset at the time SENF_PARSER_FINALIZE() is called. This allows to arbitrarily manipulate the size of the parser by changing the current offset accordingly. For dynamically sized parsers, the offset can even be any expression involving member function calls. See the documentation of the respective macros for more details.


Defines

#define  SENF_PARSER_ARRAY(name, elt_type, size)
  Define array field.
#define  SENF_PARSER_LIST(name, size, elt_type)
  Define ListParser field.
#define  SENF_PARSER_PRIVATE_LIST(name, size, elt_type)
  Define private ListParser field.
#define  SENF_PARSER_VARIANT(name, chooser, types)
  Define VariantParser field.
#define  SENF_PARSER_PRIVATE_VARIANT(name, chooser, types)
  Define private VariantParser field.
#define  SENF_PARSER_VECTOR(name, size, elt_type)
  Define VectorParser field.
#define  SENF_PARSER_PRIVATE_VECTOR(name, size, elt_type)
  Define private VectorParser field.

Control information

#define  SENF_FIXED_PARSER()
  Define fixed size parser.
#define  SENF_PARSER()
  Define dynamically sized parser.
#define  SENF_PARSER_INIT()
  Define parser initialization routine.
#define  SENF_PARSER_INHERIT(base)
  Define parser inheritance.
#define  SENF_PARSER_FINALIZE(name)
  Generate parser control members.

Parser fields

#define  SENF_PARSER_FIELD(name, type)
  Define normal parser field.
#define  SENF_PARSER_FIELD_RO(name, type)
  Define parser field (read-only).
#define  SENF_PARSER_PRIVATE_FIELD(name, type)
  Define parser field (private).
#define  SENF_PARSER_CUSTOM_FIELD(name, type, size)
  Define custom field accessor.

Bit fields

#define  SENF_PARSER_BITFIELD(name, bits, type)
  Define bit-field.
#define  SENF_PARSER_BITFIELD_RO(name, bits, type)
  Define bit-field (read-only).
#define  SENF_PARSER_PRIVATE_BITFIELD(name, bits, type)
  Define bit-field (private).

Current offset

#define  SENF_PARSER_SKIP(skip)
  Skip bytes.
#define  SENF_PARSER_SKIP_BITS(bits)
  Skip bits within bitfield group.
#define  SENF_PARSER_GOTO(name)
  Change current offset.
#define  SENF_PARSER_GOTO_OFFSET(offset)
  Change current offset to explicit value.
#define  SENF_PARSER_LABEL(name)
  Define offset label.
#define  SENF_PARSER_OFFSET(name)
  Get field offset.
#define  SENF_PARSER_FIXED_OFFSET(name)
  Get fixed field offset, if possible.
#define  SENF_PARSER_CURRENT_FIXED_OFFSET()
  Get current fixed offset, if possible.

Define Documentation

#define
SENF_FIXED_PARSER ()

Define fixed size parser.

This macro must be called using #include at the beginning of every fixed size parser using the packet parser helper macros:

struct SomeParser : public senf::PacketParserBase
{
#   include SENF_FIXED_PARSER()

The parser must directly or indirectly inherit from senf::PacketParserBase

Definition at line 302 of file ParseHelpers.hh.

#define
SENF_PARSER ()

Define dynamically sized parser.

This macro must be called using #include at the beginning of every dynamically sized parser using the packet parser helper macros:

struct SomeParser : public senf::PacketParserBase
{
#   include SENF_PARSER()

The parser must directly or indirectly inherit from senf::PacketParserBase

Definition at line 319 of file ParseHelpers.hh.

#define
SENF_PARSER_ARRAY ( name,
elt_type,
size  )

Define array field.

This macro is a special helper to define a senf::ArrayParser type field, a fixed size collection of fixed size elements.

Parameters:
[in]  name  field name
[in]  elt_type  array element type
[in]  size  constant number of elements

Definition at line 109 of file ArrayParser.hh.

#define
SENF_PARSER_BITFIELD ( name,
bits,
type  )

Define bit-field.

Bit fields are supported by a special family of parser macros. These macros simplify defining fields using the senf::IntFieldParser, senf::UIntFieldParser and senf::FlagParser parsers by keeping track of the current bit position and automatically creating the correct template parameters.

The type parameter specifies the type of bitfield to define. This value is one of

The bits parameter specifies the number of bits the field covers. For signed or unsigned fields, this value may be any numeric value from 1 to 32, for bool fields, this value must be 1.

For more information see Bit-fields

Parameters:
[in]  name  name of the bit field
[in]  bits  number of bits
[in]  type  bit field type, one of signed, unsigned or bool
See also:
SENF_PARSER_BITFIELD_RO(), SENF_PARSER_PRIVATE_BITFIELD()

Definition at line 515 of file ParseHelpers.hh.

#define
SENF_PARSER_BITFIELD_RO ( name,
bits,
type  )

Define bit-field (read-only).

Define read-only bit field. This is for bit-fields what SENF_PARSER_FIELD_RO is for ordinary fields.

See also:
SENF_PARSER_BITFIELD()
SENF_PARSER_FIELD_RO()

Definition at line 524 of file ParseHelpers.hh.

#define
SENF_PARSER_CURRENT_FIXED_OFFSET ()

Get current fixed offset, if possible.

This macro will return the current fixed offset, a compile-time constant expression. This is always possible when defining a fixed size parser.

Even in dynamically sized parsers this macro will work, if all parser defined before the current position are fixed-size parsers. This macro does not validate this condition, it will return an arbitrary incorrect value otherwise.

Precondition:
Current position preceded by fixed-size parsers only
Returns:
compile-time constant offset from parsers start

Definition at line 663 of file ParseHelpers.hh.

#define
SENF_PARSER_CUSTOM_FIELD ( name,
type,
size  )

Define custom field accessor.

This macro is used to define a field using a custom access method:

// The following is the same as SENF_PARSER_FIELD( xyz, senf::UInt16Parser )
// in a fixed size parser.

SENF_PARSER_CUSTOM_FIELD(xyz, senf::UInt16Parser, xyz_t::fixed_bytes) {
    return parse<xyz_t>( xyz_offset );
}

The macro defines the same auxiliary symbols defined by SENF_PARSER_FIELD(name, type), the accessor method however is provided by the user.

size depends on the type of parser being defined:

  • If defining a fixed parser, size is a single value bytes which must be a constant integral expression giving the fixed size of the field.
  • If defining a dynamically sized parser, size is given by two parameters bytes and init_bytes. bytes is an arbitrary (not necessarily constant) expression giving the dynamic size of the field whereas init_bytes is the constant initial size assigned to the field.
Parameters:
[in]  name  name of the field to define
[in]  type  return type of the accessor function
[in]  size  size of the field, either a single value bytes for fixed size parsers or two separate arguments bytes and init_bytes for dynamically sized parsers

Definition at line 483 of file ParseHelpers.hh.

#define
SENF_PARSER_FIELD ( name,
type  )

Define normal parser field.

The family of SENF_PARSER_FIELD() macros is used to define standard fields of a composite parser. Every field is accessed by an accessor method named after the name parameter. The field will be parsed using the type parser which must be a valid packet parser. If the current parser is defined as a fixed size parser, all sub parsers must also be fixed size, otherwise dynamically sized parser (e.g. collection parsers) are Ok.

Defining a field will always define several members:

return_type name() const
The accessor member will return the parsed value when called. For normal fields, return_type equals type, the type of the sub parser. This allows to change the value via the returned sub-parser. If the field is marked read-only (SENF_PARSER_FIELD_RO()), the return type will be type::value_type.
typedef type name_t
This typedef symbol is an alias for the fields type.
size_type const name_offset
Defined only for fixed size parsers, this gives the fixed starting offset of the field from the beginning of the parser.
size_type name_offset() const
Defined only for dynamically sized parsers, this member function will return the dynamic offset of the field from the beginning of the parser.
Parameters:
[in]  name  field name
[in]  type  parser type
See also:
SENF_PARSER_FIELD_RO(), SENF_PARSER_PRIVATE_FIELD()

Definition at line 427 of file ParseHelpers.hh.

#define
SENF_PARSER_FIELD_RO ( name,
type  )

Define parser field (read-only).

Define read-only parser field. Read-only fields may only be defined for type's which are value parsers: The parser type must have a value_type typedef member and a value() member, which returns the current value of the field.

Defining such a field really defines two accessors: A read/write private field and a read-only public accessor. The name of the private read/write field is given by adding a trailing '_' to name. The read-only public accessor is called name.

See also:
SENF_PARSER_FIELD()

Definition at line 442 of file ParseHelpers.hh.

#define
SENF_PARSER_FINALIZE ( name  )

Generate parser control members.

SENF_PARSER_FINALIZE() will generate the necessary parser control members (default constructor, parser size, parser initialization). SENF_PARSER_FINALIZE() needs not be the last macro command within the parser though it will often be the last command since SENF_PARSER_FINALIZE() does not account for fields defined later.

SENF_PARSER_FINALIZE() uses the information from SENF_PARSER_INHERIT() to construct the parsers base class (which must be a valid parser class).

defaultInit() is defined to initialize all fields defined before the call to SENF_PARSER_FINALIZE(). Fields defined later will not be initialized. If SENF_PARSER_INIT() is not used, init() is defined to call defaultInit().

The parsers size (either fixed_bytes for fixed size parsers or bytes() and init_bytes for dynamically sized parsers) is set to the current offset. By manipulating the current offset before calling SENF_PARSER_FINALIZE(), the parser size can therefore be arbitrarily manipulated. E.g., using SENF_PARSER_GOTO_OFFSET() allows to set the size to an arbitrary value.

Parameters:
[in]  name  name of the parser class currently being defined

Definition at line 387 of file ParseHelpers.hh.

#define
SENF_PARSER_FIXED_OFFSET ( name  )

Get fixed field offset, if possible.

This macro will return the fixed offset to the field name, a compile-time constant expression. This is identical to SENF_PARSER_OFFSET() when defining a fixed size parser.

Even in dynamically sized parsers this macro will work, if the field name is preceded by fixed size fields only. This macro does not validate this condition, it will return an arbitrary incorrect value otherwise.

Precondition:
Field name preceded by fixed size fields only
Parameters:
[in]  name  field or label name
Returns:
compile-time constant offset of the field from parsers start

Definition at line 648 of file ParseHelpers.hh.

#define
SENF_PARSER_GOTO ( name  )

Change current offset.

This command will change the current offset to the field or label name. Fields defined after this command will start at that position and will therefore overlay any fields defined earlier for these byte positions.

SENF_PARSER_GOTO() does not take into account the current bit position within bit fields. When passed the name of a field within a bit field group, this command will always jump to the beginning of the complete group (not the field within the bit field), even if the group covers multiple bytes before the bit field name.

Parameters:
[in]  name  field or label to jump to

Definition at line 586 of file ParseHelpers.hh.

#define
SENF_PARSER_GOTO_OFFSET ( offset  )

Change current offset to explicit value.

SENF_PARSER_GOTO_OFFSET() allows to change the current offset manually to an arbitrary value. The offset parameter depends on the type of field currently being defined.

  • If defining a fixed size parser, the offset argument is a single bytes value which is an integral constant expression to which the offset will be set.
  • If defining a dynamically sized parser, the offset argument is given by two parameters bytes and init_bytes. bytes can be any integral expression (not necessarily constant) giving the new byte position. init_bytes must be a constant integral expression and will set the current initial size of the packet to this value.
Parameters:
[in]  offset  Depending on the parser type, either single bytes value or two arguments bytes and init_size.

Definition at line 604 of file ParseHelpers.hh.

#define
SENF_PARSER_INHERIT ( base  )

Define parser inheritance.

If the a parser does not directly inherit senf::PacketParserBase, SENF_PARSER_INHERIT() must be called to define the parser's base-class. This call will additionally move the current offset to the end of the inherited parser so additional fields can be added.

struct MyParser : public BaseParser
{
#   include SENF_FIXED_PARSER() // or SENF_PARSER()

    SENF_PARSER_INHERIT(BaseParser)

If you want to define collection fields which reference auxiliary fields in the base parser, you must define the base parser as a variable parser not a fixed parser.

Parameters:
[in]  base  name of base class

Definition at line 363 of file ParseHelpers.hh.

#define
SENF_PARSER_INIT ()

Define parser initialization routine.

This macro allows to replace the default initialization code. The default init() implementation will call defaultInit() which in turn will call init() of every field defined before SENF_PARSER_FINALIZE().

SENF_PARSER_INIT() allows to replace init() with custom code:

SENF_PARSER_INIT() {
    defaultInit();
    foo() = 2;
}
Defining the initialization code manually skips the automatic call of defaultInit(), which may be performed manually. Should the initialization code be more complex, it should be placed into a non-inline private member which is called from SENF_PARSER_INIT()

Definition at line 340 of file ParseHelpers.hh.

#define
SENF_PARSER_LABEL ( name  )

Define offset label.

This command defines name as a label for the current offset. The member name_offset is defined (either as a constant for fixed size parsers or as a member function for dynamically sized parsers) to return the position at the point of label definition.

SENF_PARSER_GOTO() can later be used to jump to a position which has previously been labeled with SENF_PARSER_LABEL()

Parameters:
[in]  name  label name

Definition at line 619 of file ParseHelpers.hh.

#define
SENF_PARSER_LIST ( name,
size,
elt_type  )

Define ListParser field.

This macro is a special helper to define a senf::ListParser type field, a list of elements of type elt_type (a parser) which size is determined by size.

// The size field should be declared private or read-only (size is accessible via the list)
SENF_PARSER_PRIVATE_FIELD ( list_size_, senf::UInt16Parser );
// Define the list
SENF_PARSER_LIST ( list, list_size_, EltParser );

Here EltParser can be an arbitrary parser and need not have a fixed size.

Warning:
Realize, that the size field is controlled by the list parser. This field should therefore be declared either read-only or private and must be changed only via the list parser.
Further additional tags are supported which modify the type of list created:
bytes(size) size gives the size of the list in bytes not the number of contained elements
packetSize() Use the size of the packet to get the list size. The list will occupy all space up to the end of the packet.
transform(transform, size) The transform is applied to the size value, the value is not used directly
transform(transform, bytes(size)) The transform is applied to the size value. The value is then interpreted containing the list size in bytes not number of elements

The optional transform is a class with the following layout

struct MyTransform
{
    typedef ... value_type;
    static value_type get(other_type v);
    static other_type set(value_type v);
};

other_type is size ::value_type, the type of the value returned by the size field, whereas the value_type typedef is the arbitrary return type of the transform.

The tags are applied to the size parameter:

SENF_PARSER_LIST ( list, transform(MyTransform, list_size_), EltParser );
Warning:
There are some caveats when working with bytes() type lists:
  • You may only change the size of a contained element from a container wrapper.
  • While you hold a container wrapper, only access the packet through this wrapper or a nested wrapper either for reading or writing.

If lists are nested, you need to allocate a container wrapper for each level and may only access the packet through the lowest-level active container wrapper.

Implementation note:
These restrictions are necessary to ensure correct recalculation of the bytes field. For more info, see the comments in ListBParser.ih
Parameters:
[in]  name  field name
[in]  size  name of field giving the list size
[in]  elt_type  list element type
See also:
How to use Collection parsers
senf::ListParser the list parser API for list field access senf::ListParser_Container the list parser container API for list field access

Definition at line 308 of file ListParser.hh.

#define
SENF_PARSER_OFFSET ( name  )

Get field offset.

This macro will return the offset of the given field or label. This macro may only be used while defining the parser, normally while defining inline functions.

This macro will return the correct value when defining fixed or dynamically sized parsers.

Parameters:
[in]  name  field or label name
Returns:
offset of the field from parsers start

Definition at line 632 of file ParseHelpers.hh.

#define
SENF_PARSER_PRIVATE_BITFIELD ( name,
bits,
type  )

Define bit-field (private).

Define a bit field which is marked as private and may only be accessed from the parser class itself.

See also:
SENF_PARSER_BITFIELD()

Definition at line 534 of file ParseHelpers.hh.

#define
SENF_PARSER_PRIVATE_FIELD ( name,
type  )

Define parser field (private).

Define a parser field which is marked as private and may only be accessed from the parser class itself.

See also:
SENF_PARSER_FIELD()

Definition at line 452 of file ParseHelpers.hh.

#define
SENF_PARSER_PRIVATE_LIST ( name,
size,
elt_type  )

Define private ListParser field.

See also:
SENF_PARSER_LIST()

Definition at line 318 of file ListParser.hh.

#define
SENF_PARSER_PRIVATE_VARIANT ( name,
chooser,
types  )

Define private VariantParser field.

See also:
SENF_PARSER_VARIANT()

Definition at line 254 of file VariantParser.hh.

#define
SENF_PARSER_PRIVATE_VECTOR ( name,
size,
elt_type  )

Define private VectorParser field.

See also:
SENF_PARSER_VECTOR()

Definition at line 303 of file VectorParser.hh.

#define
SENF_PARSER_SKIP ( skip  )

Skip bytes.

Moves the offset by the given distance (which may be negative). skip depends on the type of parser being defined and is either bytes or bytes, init_bytes.

  • If defining a fixed parser, bytes must be a constant integral expression which will be added to the current offset
  • If defining a dynamically sized parser, the macro really takes two arguments, bytes and init_bytes. bytes will adjust the current field offset whereas init_bytes will adjust the parsers init_bytes value. bytes is allowed to be any integral expression, and need not be constant. The second argument init_bytes on the other hand needs to be a constant integral expression.
Parameters:
[in]  bytes  number of bytes to skip
[in]  init_bytes  only for dynamically sized parsers, value to adjust the init_bytes value with.

Definition at line 560 of file ParseHelpers.hh.

#define
SENF_PARSER_SKIP_BITS ( bits  )

Skip bits within bitfield group.

This command will skip the given number of bits within a bitfield group. This command does only affect bitfield commands. Therefore, a SENF_PARSER_SKIP_BITS command which is not followed by a bitfield command will be ignored.

Definition at line 570 of file ParseHelpers.hh.

#define
SENF_PARSER_VARIANT ( name,
chooser,
types  )

Define VariantParser field.

This macro is a special helper to define a senf::VariantParser type field.

struct SomeParser : public PacketParserBase
{
#   include SENF_PARSER()

    SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser );
    SENF_PARSER_VARIANT( content, type,
                            (novalue( disable,      senf::VoidPacketParser ))
                            (     id( uint8value,   senf::UInt8Parser      ))
                            (     id( uint16value,  senf::UInt16Parser     ))
                            (     id( uint24value,  senf::UInt24Parser     ))
                            (     id( uint32value,  senf::UInt32Parser     )) );

    SENF_PARSER_FINALIZE(SomeParser);
};

The variant content chooses one of the sub parsers depending on the type field. If type is 0, senf::VoidPacketParser is selected, if it is 1, senf::UInt8Parser and so on.

Warning:
Realize, that the chooser field is controlled by the variant parser. This field should therefore be declared either read-only or private and must be changed only via the variant parser.
The types parameter specifies the types of sub-objects supported by this variant parser. This parameter is a (Boost.Preprocessor style) sequence
(type) (type) ...
of parser types with additional optional information:
type Do not provide accessor and use the 0-based type index as key.
id(name, type) Automatically create an accessor name, a test function has_name and a function to switch to this type init_name for this type. Identical to ids(name, has_name, init_name, type)
novalue(name, type) This is like id but only provides an initializer called name and no accessor. Identical to ids(na, na, name, type)
ids(accessorId, testId, initId, type) This is again like id but the names of the accessor, test function and init function are given explicitly. Setting any of the id's to na will disable that function.
key(value, type) Use value to identity this type. The type is selected, when the chooser is equal to value
id(name, key(value, type))
novalue(name, key(value, type))
The options may be nested in this way.

Whenever an id is specified for any type, the variant itself will automatically be made private so the only access to the variant from the outside is via the accessors.

The functions defined by specifying an id are:

name_t The type for this specific variant value if not novalue.
name_t name() Return the variant value at this id if not novalue.
void init_name() Set the variant to have a value of this type. If the field is novalue, the init_ prefix is omitted.
bool has_name() Return true, if the variant currently holds this kind of value, false otherwise. Only if not novalue.

If key specs are given, they designate the value to expect in the chooser field to select a specific variant type. If the chooser value does not match any key, the variant will be initialized to the first type.

Further additional tags are supported which modify the way, the chooser field is interpreted:

transform(transform, chooser) The transform is applied to the chooser value, the value is not used directly

The optional transform is a class with the following layout

struct MyTransform
{
    typedef ... value_type;
    static value_type get(other_type v);
    static other_type set(value_type v);
};
other_type is the chooser ::value_type whereas the value_type typedef is the arbitrary return type of the transform.

The tags are applied to the chooser parameter:

Parameters:
[in]  name  name of the field
[in]  chooser  name of the field choosing the variant to use
[in]  types  a Boost.Preprocessor style sequence of sub-parser types
See also:
senf::VariantParser for the VariantParser API
SENF_PARSER_PRIVATE_VARIANT()

Definition at line 245 of file VariantParser.hh.

#define
SENF_PARSER_VECTOR ( name,
size,
elt_type  )

Define VectorParser field.

This macro is a special helper to define a senf::VectorParser type field, a vector of elements of type elt_type (a parser) which size is given by the size field.

// The size field should be declared private (size is accessible via the vector)
SENF_PARSER_PRIVATE_FIELD ( vec_size_, senf::UInt16Parser );
// Define the vector, here it has 32bit unsigned integer elements
SENF_PARSER_VECTOR        ( vec,       vec_size_, senf::UInt32Parser );
Warning:
Realize, that the size field is controlled by the vector parser. This field should therefore be declared either read-only or private and must be changed only via the vector parser.
Further additional tags are supported which modify the way, the size field is interpreted:
bytes(size) size gives the size of the vector in bytes not the number of contained elements
packetSize() Use the size of the packet to get the vector size. The vector will occupy all space up to the end of the packet.
transform(transform, size) The transform is applied to the size value, the value is not used directly

The optional transform is a class with the following layout

struct MyTransform
{
    typedef ... value_type;
    static value_type get(other_type v);
    static other_type set(value_type v);
};
other_type is the size ::value_type where as the value_type typedef is the arbitrary return type of the transform.

The tags are applied to the size parameter:

SENF_PARSER_VECTOR ( vec, transform(MyTransform, vec_size_), senf::UInt32Parser );
SENF_PARSER_VECTOR ( vec, packetSize(), senf::UInt32Parser );
Parameters:
[in]  name  field name
[in]  size  name of field giving the vector size
[in]  elt_type  vector element type
See also:
How to use Collection parsers
senf::VectorParser the vector parser API for vector field access senf::VectorParser_Container the vector parser container API for vector field access

Definition at line 293 of file VectorParser.hh.