Packets: Add SENF_PACKET_PARSER_DEFINE_[FIXED_]FIELDS_OFFSET
[senf.git] / Packets / PacketParser.hh
1 // Copyright (C) 2007 
2 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
3 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
4 //     Stefan Bund <g0dil@berlios.be>
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the
18 // Free Software Foundation, Inc.,
19 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 /** \file
22     \brief PacketParser public header */
23
24 /** \defgroup packetparser The PacketParser facility
25     
26     The PacketParser facility provides a framework to implement very lightweight classes which parse
27     the raw content of a packet into meaningful values. PacketParsers are always passed around
28     <em>by value</em>, they can be understood as pointers into the packet data with added type
29     information providing parsing functions.
30
31     Parsers are built hierarchically. A high-level parser will return other parsers when accessing
32     an element (Example: Asking an EthernetParser for the ethertype field by calling the parsers \c
33     type() member will return an \c UInt16 parser). The lowest level building blocks then return the
34     values. This hierarchical structure greatly simplifies building complex parsers.
35
36     Since parsers are very lightweight and are passed by value, packet fields are accessed using the
37     corresponding accessor method:
38     \code
39       SomePacket p (...)
40       SomePacket q (...)
41
42       // Assign new value to an integer parser
43       p->someField() = 10;
44
45       // Write out above value
46       std::cerr << p->someField() << "\n";
47
48       // Use the generic parser-assignment operator '<<' to copy field values
49       p->someVector()[1].someOtherField() << q->someField();
50       p->someVector() << q->someVector()
51     \endcode
52
53     Here \c someField(), \c someOtherField() and \c someVector() are accessor methods named after
54     the field name. Each returns a parser object. Simple parsers can be used like their
55     corresponding basic type (e.g. a Parse_UInt16 field can be used like an unsigned integer), more
56     complex parsers provide type specific access members. Assigning a value to a parser will change
57     the underlying representation (the packet data). 
58
59     More complex parsers (especially those representing a collection of values) provide an
60     additional wrapper class for mutating access (e.g. Parse_Vector provides a container wrapper
61     with am STL compatible random-access sequence interface). See the documentation of the specific
62     parser for the wrapper specification.
63
64     Every parser is derived from senf::PacketParserBase. This class provides the necessary
65     housekeeping information and provides the parsers with access to the data.
66  */
67
68 #ifndef HH_PacketParser_
69 #define HH_PacketParser_ 1
70
71 // Custom includes
72 #include <boost/utility/enable_if.hpp>
73 #include <boost/type_traits.hpp>
74 #include <boost/optional.hpp>
75 #include "Utils/SafeBool.hh"
76 #include "PacketTypes.hh"
77 #define HH_PacketData_DeclOnly
78 #include "PacketData.hh"
79 #undef HH_PacketData_DeclOnly
80
81 #include "PacketParser.mpp"
82 ///////////////////////////////hh.p////////////////////////////////////////
83
84 namespace senf {
85     
86     /** \brief Parser Base class
87
88         Parsers come in two favors: fixed and dynamically sized parsers. A <em>fixed size
89         parser</em> has a constant size, it will always parse a fixed number of bytes. The low-level
90         'final'  parsers (like the integer parsers) are fixed size parsers as are composite parsers
91         built up only of fixed-size fields.
92
93         A <em>dynamically sized</em> parser on the other hand infers it's size from the contents of
94         the data parsed. Any parser containing at least one dynamically sized sub-parser will itself
95         be dynamically sized.
96         
97         Both kinds of parser need to derive from PacketParserBase and implement several required
98         members. Which members to implement depends on the parsers flavor. There are two ways how to
99         do this.
100         \li If the parser just consists of a simple sequence of consecutive fields (sub-parsers),
101             the \ref SENF_PACKET_PARSER_DEFINE_FIELDS and \ref
102             SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros provide a simple and convenient way to
103             define the packet
104         \li In more complex cases, you need to implement the necessary members manually.
105
106         This documentation is about the manual implementation. You should nevertheless read through
107         this to understand, what above macros are doing.
108
109         The following example documents the interface (which must be) provided by a parser:
110         \code
111           struct FooParser : public PacketParserBase
112           {
113               FooParser(data_iterator i, state_type s) : PacketParserBase(i,s) {}
114
115               // If this parser has a fixed size, you must define this size here This definition
116               // allows the parser to be used within the list, vector and array parsers static
117               static const size_type fixed_bytes = some_constant_size;
118
119               // If the parser does not have a fixed size, you must implement the bytes() member to
120               // return the size. ONLY EVER DEFINE ONE OF fixed_bytes OR bytes().
121               size_type bytes() const;
122
123               // If you define bytes(), you also need to define the init_bytes. This is the number
124               // of bytes to allocate when creating a new object
125               static const size_type init_bytes = some_constant_size;
126
127               // You also may define an init() member. This will be called to initialize a newly
128               // created data object. The default implementation just does nothing.
129               void init() const;
130
131               // ////////////////////////////////////////////////////////////////////////
132
133               // Add here members returning (sub-)parsers for the fields. The 'parse' member is 
134               // used to construct the sub-parsers. This member either takes an iterator to the
135               // data to be parsed or just an offset in bytes.
136
137               senf::Parse_UInt16 type() const { return parse<Parse_UInt16>( 0 ); }
138               senf::Parse_UInt16 size() const { return parse<Parse_UInt16>( 2 ); }
139           };
140         \endcode
141         
142         You should never call the \c bytes() member of a parser directly. Instead you should use the
143         freestanding senf::bytes() function. This function will return the correct size irrespective
144         of the parsers flavor. You may access \c fixed_bytes directly, however be aware that this
145         will restrict your code to fixed size parsers (which depending on the circumstances may be
146         exactly what you want).
147
148         In the same way, don't access \c init_bytes directly, always use the senf::init_bytes
149         meta-function class which correctly supports fixed size parsers.
150
151         \ingroup packetparser
152       */
153     class PacketParserBase
154     {
155     public:
156         ///////////////////////////////////////////////////////////////////////////
157         // Types
158
159         typedef detail::packet::iterator data_iterator; ///< Raw data iterator type
160         typedef detail::packet::size_type size_type; ///< Unsigned integral type
161         typedef detail::packet::difference_type difference_type; ///< Signed integral type
162         typedef detail::packet::byte byte; ///< Unsigned 8bit value, the raw value type
163         typedef PacketData * state_type; ///< Type of the 'state' parameter
164
165         ///////////////////////////////////////////////////////////////////////////
166         ///\name Structors and default members
167         ///@{
168
169         // no default constructor
170         // default copy
171         // default destructor
172         // no conversion constructors
173
174         ///@}
175         ///////////////////////////////////////////////////////////////////////////
176
177         data_iterator i() const;        ///< Return beginning of data to parse
178                                         /**< The parser is expected to interpret the data beginning
179                                              here. The size of the interpreted is given by
180                                              <tt>senf::bytes(</tt><em>parser
181                                              instance</em><tt>)</tt>. */
182         state_type state() const;       ///< Return state of this parser
183                                         /**< The value returned should be interpreted as an opaque
184                                              value provided just to be forwarded to other
185                                              parsers. */
186         PacketData & data() const;      ///< Access the packets raw data container
187                                         /**< This member will return the raw data container holding
188                                              the data which is parsed by \c this parser. */
189
190         void init() const;              ///< Default implementation
191                                         /**< This is just an empty default
192                                              implementation. Re-implement this member in your own
193                                              parsers if needed. */
194
195     protected:
196         PacketParserBase(data_iterator i, state_type s); ///< Standard constructor
197                                         /**< This is the constructor used by most parsers. The
198                                              parameters are just forwarded from the derived classes
199                                              constructor parameters. */
200         PacketParserBase(data_iterator i, state_type s, size_type size); 
201                                         ///< Size checking constructor
202                                         /**< In addition to the standard constructor, this
203                                              constructor will validate, that there is enough data in
204                                              the raw data container to parse \a size bytes after \a
205                                              i.
206
207                                              This constructor is called by all 'final' parsers
208                                              (e.g. the integer parsers) and \e only by those
209                                              parsers. Most parsers do \e not check the validity of
210                                              the iterator, this is delayed until the very last
211                                              parser. This allows to partial parse truncated
212                                              packets.
213
214                                              \throw TruncatedPacketException if the raw data
215                                                  container does not hold at least \a size bytes
216                                                  beginning at \a i. */
217
218         bool check(size_type size);     ///< Check size of data container
219                                         /**< \returns \c true, if the data container holds at least
220                                              \a size beginning at i(), \c false otherwise. */
221         void validate(size_type size);  ///< Validate size of data container
222                                         /**< \throws TruncatedPacketException if the raw data
223                                              container does not hold at least \a size bytes
224                                              beginning at i(). */
225
226         template <class Parser> Parser parse(data_iterator i) const; ///< Create sub-parser
227                                         /**< Creates a new instance of \a Parser to parse data
228                                              beginning at \a i. Automatically passes \a state() to
229                                              the new parser. */
230         template <class Parser> Parser parse(size_type n) const; ///< Create sub-parser
231                                         /**< Creates a new instance of \a Parser to parse data
232                                          * beginning at i()<tt> + </tt>\a n. Automatically passes \a
233                                              state() to the new parser. */
234
235         void defaultInit() const;       ///< Default implementation
236                                         /**< This is just an empty default
237                                              implementation. Re-implement this member in your own
238                                              parsers if needed. */
239
240     private:
241         data_iterator end();
242
243         data_iterator i_;
244         PacketData * data_;
245
246         template <class Parser> friend class SafePacketParser;
247     };
248
249     /** \brief Return raw size parsed by the given parser object
250         
251         This function will either call <tt>p.bytes()</tt> or return <tt>Parser::fixed_bytes</tt>
252         depending on the type of parser.
253
254         The value returned does \e not take into account the amount of data actually available. So
255         you always need to validate this value against the packet size if you directly access the
256         data. The standard low-level parses all do this check automatically to guard against
257         malformed packets.
258
259         \param[in] p Parser object to check
260         \returns number of bytes this parser expects to parser
261         \ingroup packetparser
262      */
263     template <class Parser>
264     PacketParserBase::size_type bytes(Parser p);
265     
266     namespace detail { template <class Parser> class ParserInitBytes; }
267
268     /** \brief Return number of bytes to allocate to new object of given type
269
270         This meta-function is called like
271         \code
272             senf::init_bytes<SomeParser>::value
273         \endcode
274
275         This expression evaluates to a compile-time constant integral expression of type
276         senf::PacketParserBase::size_type. This meta-function will return \c Parser::fixed_bytes or
277         \c Parser::init_bytes depending on the type of parser.
278
279         \param[in] Parser The Parser to return init_bytes for
280         \returns Number of bytes to allocate to the new object
281         \ingroup packetparser
282      */
283     template <class Parser>
284     struct init_bytes : public detail::ParserInitBytes<Parser>
285     {};
286
287     /** \brief Generic parser copying
288
289         This operator allows to copy the values of identical parsers. This operation does \e not
290         depend on the parsers detailed implementation, it will just replace the data bytes of the
291         target parser with those from the source parser. This allows to easily copy around complex
292         packet substructures.
293
294         This operation is different from the ordinary assignment operator: It does not change the \a
295         target parser, it changes the data referenced by the \a target parser.
296
297         \ingroup packetparser
298      */
299     template <class Parser>
300     typename boost::enable_if< 
301         boost::is_base_of<PacketParserBase, Parser>,
302         Parser >::type
303     operator<<(Parser target, Parser source);
304
305     /** \brief Generic parser value assignment
306
307         This operator allows to assign a value to parsers which implement a <tt>value(</tt>\a
308         value<tt>)</tt> member. This operator allows to use a common syntax for assigning values or
309         parsers to a parser. 
310
311         \ingroup packetparser
312      */
313     template <class Parser, class Value>
314     typename boost::enable_if_c < 
315         boost::is_base_of<PacketParserBase, Parser>::value 
316             && ! boost::is_base_of<PacketParserBase, Value>::value,
317         Parser >::type
318     operator<<(Parser target, Value const & value);
319
320     /** \defgroup packetparsermacros Helper macros for defining new packet parsers
321         
322         To simplify the definition of simple packet parsers, several macros are provided. Before
323         using these macros you should familiarize yourself with the packet parser interface as
324         described in senf::PacketParserBase.
325
326         These macros simplify providing the above defined interface. A typical packet declaration
327         using these macros has the following form (This is a concrete example from the definition of
328         the ethernet packet in <tt>DefaultBundle//EthernetPacket.hh</tt>)
329         \code
330             struct Parse_EthVLan : public senf::PacketParserBase
331             {
332                 SENF_PACKET_PARSER_INIT(Parse_EthVLan);
333
334                 // ////////////////////////////////////////////////////////////////////////
335
336                 typedef senf::Parse_UIntField < 0,  3 > Parse_Priority;
337                 typedef senf::Parse_Flag          < 3 > Parse_CFI;
338                 typedef senf::Parse_UIntField < 4, 16 > Parse_VLanId;
339                 typedef senf::Parse_UInt16              Parse_Type;
340
341                 SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
342                     ((OverlayField)( priority, Parse_Priority ))
343                     ((OverlayField)( cfi,      Parse_CFI      ))
344                     ((Field       )( vlanId,   Parse_VLanId   ))
345                     ((Field       )( type,     Parse_Type     )) 
346                 );
347             };
348         \endcode
349
350         The macros take care of the following:
351         \li They define the accessor functions returning parsers of the given type.
352         \li They automatically calculate the offset of the fields from the preceding fields.
353         \li The macros provide a definition for \c init() 
354         \li The macros define the \c bytes(), \c fixed_bytes and \c init_bytes members as needed.
355
356         You may define either a fixed or a dynamically sized parser. Fixed size parsers are defined
357         using \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS, dynamically sized parsers are defined
358         using \ref SENF_PACKET_PARSER_DEFINE_FIELDS. The different members are implemented such
359         that:
360         
361         \li The needed parser constructor is defined
362         \li \c init() calls \c defaultInit(). \c defaultInit() is defined to call \c init() on each
363             of the fields.
364         \li \c bytes() (on dynamically sized parser) respectively \c fixed_bytes (on fixed size
365             parsers) is defined to return the sum of the sizes of all fields.
366         \li On dynamically sized parsers, \c init_bytes is defined to return the sum of the
367             \c init_size's of all fields
368
369         The central definition macros are \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS and \ref
370         SENF_PACKET_PARSER_DEFINE_FIELDS. The argument to both has the same structure. It is a
371         (boost preprocessor style) sequence of field definitions where each field definition
372         provides the builder macro to use and the name and type of the field to define:
373         \code
374           SENF_PACKET_PARSER_DEFINE[_FIXED]_FIELDS(
375               (( <builder> )( <name>, <type> ))
376               ...
377           )
378         \endcode
379         
380         For each field, this command will define
381         \li A method \a name() returning an instance of the \a type parser
382         \li \a name<tt>_t</tt> as a typedef for \a type, the fields value
383         \li \a name<tt>_offset</tt> to give the offset of the field from the beginning of the
384             parser. If the parser is a fixed size parser, this will be a static constant, otherwise
385             it will be a method.
386
387         The \a builder argument selects, how the field is defined
388         \li <tt>Field</tt> defines a field and increments the current position by the size of the
389             field
390         \li <tt>OverlayField</tt> defines a field like <tt>Field</tt> but does \e not increment the
391             position. In the above example, this is used to overlay the different bitfield parsers:
392             All overlaying bitfield parser except the last one (the one with the highest bit
393             numbers) is marked as OverlayField.
394
395         The \a name argument defines the name of the accessor method.
396
397         The \a type argument is the parser to return for that field. Since none of the arguments may
398         contain a comma, <em>This argument cannot be a multi-parameter template</em>. Always use
399         typedefs to access templated parsers as shown above.
400
401         The \ref SENF_PACKET_PARSER_INIT macro defines the constructor and the \c init() member. If
402         you want to provide your own \c init() implementation, use \ref
403         SENF_PACKET_PARSER_NO_INIT. The first statement in your init method should probably to call
404         \c defaultInit(). This will call the \c init() member of all the fields. Afterwards you can
405         set up the field values as needed:
406         \code
407           struct SomePacket : public senf::PacketParserBase
408           {
409               SENF_PACKET_PARSER_NO_INIT(SomePacket);
410         
411               typedef senf::Parse_UInt8 Parse_Type;
412               typedef senf::Parse_Vector< senf::Parse_UInt32,
413                                           senf::SimpleVectorSizer<senf::Parse_UInt16>
414                                         > Parse_Elements;
415
416               SENF_PACKET_PARSER_DEFINE_FIELDS(
417                   ((Field)( type,     Parse_Type     ))
418                   ((Field)( elements, Parse_Elements ))
419               );
420
421               void init() const {
422                   defaultInit();
423                   type() = 0x01;
424                   elements().push_back(0x01020304u);
425               }
426           }
427         \endcode
428         
429         \ingroup packetparser
430      */
431
432     /** \brief Define initialization members of a parser
433         
434         This macro defines the packet parser constructor and the \c init() member. \c init() is
435         defined to just call \c defaultInit() which is defined by the other macros to call \c init()
436         on each of the parsers fields.
437
438         \ingroup packetparsermacros
439         \hideinitializer
440      */
441 #   define SENF_PACKET_PARSER_INIT(name)                                                          \
442     name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {}                          \
443     void init() const { defaultInit(); }
444
445     /** \brief Define initialization members of a parser except init()
446         
447         This macro is like SENF_PACKET_PARSER_INIT but does \e not define \c init(). This allows you
448         to provide your own implementation. You should call \c defaultInit() first before
449         initializing your data fields.
450
451         \ingroup packetparsermacros
452         \hideinitializer
453      */
454 #   define SENF_PACKET_PARSER_NO_INIT(name)                                                       \
455     name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {}
456
457     /** \brief Define fields for a dynamically sized parser
458
459         Define the fields as specified in \a fields. This macro supports dynamically sized
460         subfields, the resulting parser will be dynamically sized.
461
462         \ingroup packetparsermacros
463         \hideinitializer
464      */
465 #   define SENF_PACKET_PARSER_DEFINE_FIELDS(fields)                                               \
466     SENF_PACKET_PARSER_I_DEFINE_FIELDS(0,fields)
467         
468     /** \brief Define fields for a dynamically sized parser (with offset)
469
470         Define the fields as specified in \a fields. This macro supports dynamically sized
471         subfields, the resulting parser will be dynamically sized.
472
473         The \a offset argument gives the byte offset at which to start parsing the fields. This
474         helps defining extended parser deriving from a base parser:
475         \code
476            struct ExtendedParser : public BaseParser
477            {
478                SENF_PACKET_PARSER_NO_INIT(ExtendedParser);
479         
480                SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(senf::bytes(BaseParser(*this)),
481                  ( ... fields ... ) );
482
483                void init() {
484                    BaseParser::init();
485                    defaultInit();
486                    // other init code
487                }
488            }
489         \endcode
490
491         \ingroup packetparsermacros
492         \hideinitializer
493      */
494 #   define SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(offset,fields)                                 \
495     SENF_PACKET_PARSER_I_DEFINE_FIELDS(offset,fields)
496
497     /** \brief Define fields for a fixed size parser
498
499         Define the fields as specified in \a fields. This macro only supports fixed size
500         subfields, the resulting parser will also be a fixed size parser.
501
502         \ingroup packetparsermacros
503         \hideinitializer
504      */
505 #   define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(fields)                                         \
506     SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(0,fields)
507
508     /** \brief Define fields for a fixed size parser
509
510         Define the fields as specified in \a fields. This macro only supports fixed size
511         subfields, the resulting parser will also be a fixed size parser.
512
513         The \a offset argument gives the byte offset at which to start parsing the fields. This
514         helps defining extended parser deriving from a base parser:
515         \code
516            struct ExtendedParser : public BaseParser
517            {
518                SENF_PACKET_PARSER_NO_INIT(ExtendedParser);
519
520                SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(BaseParser::fixed_bytes,
521                  ( ... fields ... ) );
522
523                void init() {
524                    BaseParser::init();
525                    defaultInit();
526                    // other init code
527                }
528            }
529         \endcode
530
531         \ingroup packetparsermacros
532         \hideinitializer
533      */
534 #   define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(offset,fields)                           \
535     SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(offset,fields)
536
537     struct VoidPacketParser 
538         : public PacketParserBase
539     {
540         SENF_PACKET_PARSER_INIT(VoidPacketParser);
541     };
542
543     /** \brief Iterator re-validating Parser wrapper
544
545         An ordinary parser will be invalidated whenever the raw data container's size is
546         changed. This can complicate some algorithms considerably.
547
548         This wrapper will update the parsers iterator (the value returned by the i() member) on
549         every access. This ensures that the iterator will stay valid.
550
551         \attention Beware however, if you insert or remove data before the safe wrapper, the
552             location will \e not be updated accordingly and therefore the parser will be
553             invalid.
554
555         Additionally a SafePacketparser has an uninitialized state. The only allowed operations in
556         this state are the boolean test for validity and assigning another parser.
557       */
558     template <class Parser>
559     class SafePacketParser
560         : public SafeBool< SafePacketParser<Parser> >
561     {
562     public:
563         ///////////////////////////////////////////////////////////////////////////
564         // Types
565
566         ///////////////////////////////////////////////////////////////////////////
567         ///\name Structors and default members
568         ///@{
569
570         // default copy constructor
571         // default copy assignment
572         // default destructor
573         SafePacketParser();             ///< Create an empty uninitialized SafePacketParser
574
575         // conversion constructors
576         SafePacketParser(Parser parser); ///< Initialize SafePacketParser from \a parser
577
578         SafePacketParser & operator=(Parser parser); ///< Assign \a parser to \c this
579
580         ///@}
581         ///////////////////////////////////////////////////////////////////////////
582
583         Parser operator*() const;       ///< Access the stored parser
584                                         /**< On every access, the stored parsers iterator will be
585                                              updated / re-validated. */
586         Parser const * operator->() const; ///< Access the stored parser
587                                         /**< On every access, the stored parsers iterator will be
588                                              updated / re-validated. */
589         bool boolean_test() const;      ///< Check validity
590
591     protected:
592
593     private:
594         mutable boost::optional<Parser> parser_;
595         senf::safe_data_iterator i_;
596     };
597
598 }
599
600 ///////////////////////////////hh.e////////////////////////////////////////
601 #include "PacketParser.cci"
602 #include "PacketParser.ct"
603 #include "PacketParser.cti"
604 #endif
605
606 \f
607 // Local Variables:
608 // mode: c++
609 // fill-column: 100
610 // c-file-style: "senf"
611 // indent-tabs-mode: nil
612 // ispell-local-dictionary: "american"
613 // compile-command: "scons -u test"
614 // comment-column: 40
615 // End:
616
617 //  LocalWords:  templated PacketParser defgroup packetparser PacketParsers li
618 //  LocalWords:  EthernetParser ethertype UInt senf PacketParserBase tt
619 //  LocalWords:  struct FooParser const init endcode ingroup param SomeParser
620 //  LocalWords:  ethernet DefaultBundle EthernetPacket hh EthVLan UIntField CFI
621 //  LocalWords:  VLanId OverlayField cfi vlanId accessor defaultInit bitfield
622 //  LocalWords:  SomePacket SimpleVectorSizer packetparsermacros Fraunhofer std
623 //  LocalWords:  hideinitializer Institut fuer offene Kommunikationssysteme STL
624 //  LocalWords:  FOKUS Kompetenzzentrum Satelitenkommunikation SatCom Bund cerr
625 //  LocalWords:  berlios dil Structors someField someVector someOtherField
626 //  LocalWords:  TruncatedPacketException