switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Packets / GenericTLV.hh
index 3c4f12d..5ba1847 100644 (file)
@@ -2,23 +2,28 @@
 //
 // Copyright (C) 2009
 // Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Thorsten Horstmann <tho@berlios.de>
 //
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
+// The contents of this file are subject to the Fraunhofer FOKUS Public License
+// Version 1.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at 
+// http://senf.berlios.de/license.html
 //
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
+// The Fraunhofer FOKUS Public License Version 1.0 is based on, 
+// but modifies the Mozilla Public License Version 1.1.
+// See the full license text for the amendments.
 //
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+// Software distributed under the License is distributed on an "AS IS" basis, 
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
+// for the specific language governing rights and limitations under the License.
+//
+// The Original Code is Fraunhofer FOKUS code.
+//
+// The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
+// (registered association), Hansastraße 27 c, 80686 Munich, Germany.
+// All Rights Reserved.
+//
+// Contributor(s):
+//   Thorsten Horstmann <tho@berlios.de>
 
 /** \file
     \brief GenericTLV public header */
 #define HH_SENF_Packets_GenericTLV_ 1
 
 // Custom includes
+#include <boost/ptr_container/ptr_map.hpp>
 #include <senf/Packets/Packets.hh>
 #include <senf/Utils/type_traits.hh>
+#include <senf/Utils/singleton.hh>
 
 //#include "GenericTLV.hh.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 
 namespace senf {
+
     /** \brief Base class for generic TLV parsers
-       
+
        This abstract base class can be used to define generic TLV parsers. The following
        class structure is assumed:
        \image html GenericTLV.png
-        
+
         Your TLVParser base class has to define a \c type and a \c length field:
         \code
         struct MyTLVParserBase : public senf::PacketParserBase
@@ -51,9 +58,9 @@ namespace senf {
             SENF_PARSER_FINALIZE ( MyTLVParserBase           );
         };
         \endcode
-       
+
         Your concrete TLV parsers will inherit from this base class and have to define a specific
-        value field and a \c TYPEID member:
+        value field and a \c typeId member:
         \code
         struct MyConcreteTLVParser : public MyTLVParserBase
         {
@@ -61,35 +68,35 @@ namespace senf {
             SENF_PARSER_INHERIT  ( MyTLVParserBase             );
             SENF_PARSER_FIELD    ( myValue, senf::UInt32Parser );
             SENF_PARSER_FINALIZE ( MyConcreteTLVParser         );
-         
+
             SENF_PARSER_INIT() {
-                type() = TYPEID;
+                type() = typeId;
                 length_() = 4;
-            }        
-            static const type_t::value_type TYPEID = 0x42;
+            }
+            static const type_t::value_type typeId = 0x42;
         };
         \endcode
-       
+
         With GenericTLVParserBase you can define a generic parser class which provides
         members to access the value data and and to cast the parser to a concrete tlv
-        parser:   
+        parser:
         \code
         struct MyGenericTLVParser : public senf::GenericTLVParserBase<MyTLVParserBase>
         {
             typedef senf::GenericTLVParserBase<MyTLVParserBase> base;
             MyGenericTLVParser(data_iterator i, state_type s) : base(i,s) {}
-            
+
             // members for your generic TLV parser...
         };
         \endcode
-        
+
         If your generic TLV parser just inherits from GenericTLVParserBase and doesn't
         add any additional functionality you can use a simple \c typedef as well:
         \code
         typedef senf::GenericTLVParserBase<MyTLVParserBase> MyGenericTLVParser;
         \endcode
-        
-        This generiv tlv parser can now be used for example in a list:
+
+        This generic tlv parser can now be used for example in a list:
         \code
         class MyTestPacketParser : public senf::PacketParserBase
         {
@@ -99,7 +106,7 @@ namespace senf {
             SENF_PARSER_FINALIZE ( MyTestPacketParser );
         };
         \endcode
-        
+
         Now, you can access the TLV parsers in the list in a generic way or you
         can cast the parsers to some concrete tlv parser:
         \code
@@ -107,46 +114,49 @@ namespace senf {
         typedef MyTestPacket::Parser::tlv_list_t::container container_t;
         container_t tlvContainer (p->tlv_list() );
         optContainer_t::iterator listIter (tlvContainer.begin());
-        
+
         // listIter points to a MyGenericTLVParser, so you have generic access:
         listIter->type() = 0x42;
         listIter->value( someRangeOfValueData);
-        
+
         // cast to an instance of MyConcreteTLVParser:
         if (listIter->is<MyConcreteTLVParser>()) {
             MyConcreteTLVParser concreteTLVParser ( listIter->as<MyConcreteTLVParser>());
             concreteTLVParser.myValue() = 0xabababab;
         }
-        
+
         // add a MyConcreteTLV to the list:
         MyConcreteTLVParser tlv ( tlvContainer.push_back_space().init<MyConcreteTLVParser>());
         tlv.myValue() = 0xffff;
-        \endcode  
+        \endcode
 
-        \see 
-            IPv6GenericOptionTLVParser, WLANGenericInfoElementParser, MIHGenericTLVPacketParser 
+        \see
+            IPv6GenericOptionParser, WLANGenericInfoElementParser, MIHGenericTLVParser \n
+            GenericTLVParserRegistry
      */
     template <class Base>
     class GenericTLVParserBase : public Base
     {
     public:
-        GenericTLVParserBase(senf::PacketParserBase::data_iterator i, senf::PacketParserBase::state_type s) 
+        GenericTLVParserBase(senf::PacketParserBase::data_iterator i, senf::PacketParserBase::state_type s)
             : Base(i,s) {}
-    
-        senf::PacketParserBase::size_type bytes();
+
+        senf::PacketParserBase::size_type bytes() const;
         void init() const;
 
         template <class Parser>
         Parser init();
-        
+
         template <class Parser>
-        Parser as();
-        
+        Parser as() const;
+
         template <class Parser>
-        bool is();
+        bool is() const;
 
         senf::PacketInterpreterBase::range value() const;
-        
+
+        void dump(std::ostream & os) const;
+
 #ifndef DOXYGEN
         template<class ForwardReadableRange>
         void value(ForwardReadableRange const & val,
@@ -158,26 +168,154 @@ namespace senf {
 
         template <class Type, class ForwardReadableRange>
         void value(std::pair<Type, ForwardReadableRange> const & val,
-                typename boost::enable_if<boost::is_convertible<Type, typename Base::type_t::value_type> >::type * = 0);        
+                typename boost::enable_if<boost::is_convertible<Type, typename Base::type_t::value_type> >::type * = 0);
 #else
         template<class ForwardReadableRange>
         void value(ForwardReadableRange const & val);
-        
+
         template <class ForwardReadableRange>
         void value(std::pair<typename Base::type_t::value_type, ForwardReadableRange> const & val);
-#endif   
-        
+#endif
+
     private:
         template<class ForwardReadableRange>
         void value_(ForwardReadableRange const &range);
-        
+
         Base & self();
         Base const & self() const;
     };
-}
 
 
-///////////////////////////////hh.e////////////////////////////////////////
+    namespace detail {
+        template <class BaseParser>
+        struct GenericTLVParserRegistry_EntryBase {
+            virtual ~GenericTLVParserRegistry_EntryBase() {}
+            virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const = 0;
+            virtual PacketParserBase::size_type bytes(GenericTLVParserBase<BaseParser> const & parser) const = 0;
+        };
+
+        template <class BaseParser, class Parser>
+        struct GenericTLVParserRegistry_Entry
+            : GenericTLVParserRegistry_EntryBase<BaseParser>
+        {
+            virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const;
+            virtual PacketParserBase::size_type bytes(GenericTLVParserBase<BaseParser> const & parser) const;
+        };
+
+        //Helper Functor for STL-compatible predicate (E.g. find_if, for_each ...)
+        template <class BaseParser, class Parser>
+        class Predicate
+        {
+            public:
+                bool operator() (BaseParser const &p) const {
+                    return p.template is<Parser>();
+                }
+        };
+    }
+
+    /** \brief TLV parser registration facility
+
+        The %GenericTLVParserRegistry provides a generic facility to globally register concrete
+        TLV parser by the type value. The concrete TLV parser must therefore provide a \c typeId
+        member. See GenericTLVParserBase for details about the assumed class structure.
+
+        Every registry is identified by the base tlv parser class. Parsers can be registered
+        statically only:
+        \code
+        GenericTLVParserRegistry<MyTLVParserBase>::RegistrationProxy<ConcreteTLVParser>
+            registerConcreteTLVParser;
+        \endcode
+        This global variable declaration will register ConcreteTLVParser. The variable
+        registerConcreteTLVParser is a dummy. It's only function is to force the call of
+        it's constructor during global construction time. This static registration only
+        works when the symbol is included into the final binary.
+
+        To simplify the registration the \ref SENF_PACKET_TLV_REGISTRY_REGISTER macro can be used.
+        The \c ConreteTLVParser must therefore provide a \c Registry typedef pointing to the
+        %GenericTLVParserRegistry; typically you put this typedef to the TLVBaseParser class.
+        \code
+        struct MyTLVParserBase : public senf::PacketParserBase
+        {
+            ...
+            typedef GenericTLVParserRegistry<MyTLVParserBase> Registry;
+        };
+        struct MyConcreteTLVParser : public MyTLVParserBase
+        {
+            ....
+            static const type_t::value_type typeId = 0x42;
+            void dump(std::ostream & os) const;
+        };
+
+        // register MyConcreteTLVParser to the MyTLVParserBase-Registry with the type id 0x42:
+        SENF_PACKET_TLV_REGISTRY_REGISTER( MyConcreteTLVParser );
+        \endcode
+
+        The registry provides a dump() member to dump an instance of a generic TLV parser.
+        If the type value of the given TLV parser is registered the generic tlv will be
+        casted to the registered concrete TLV parser and the dump member from this parser
+        will be called.
+
+        \see
+            GenericTLVParserBase for the general TLV class structure \n
+            IPv6OptionParser::Registry, WLANInfoElementParser::Registry,
+            MIHBaseTLVParser::Registry
+     */
+    template <class BaseParser, class Keytype = typename BaseParser::type_t::value_type>
+    class GenericTLVParserRegistry
+        : public senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >
+    {
+        typedef boost::ptr_map<Keytype,
+            detail::GenericTLVParserRegistry_EntryBase<BaseParser> > Map;
+        Map map_;
+
+        GenericTLVParserRegistry() {};
+    public:
+        using senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >::instance;
+        friend class senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >;
+
+        template <class PacketParser>
+        struct RegistrationProxy {
+            RegistrationProxy();
+        };
+
+        template <typename Parser>
+        void registerParser();
+
+        typedef GenericTLVParserBase<BaseParser> GenericTLVParser;
+
+        bool isRegistered(GenericTLVParserBase<BaseParser> const & parser) const;
+        bool isRegistered(Keytype const & key) const;
+
+        void dump(GenericTLVParser const & parser, std::ostream & os) const;
+        void dump(GenericTLVParser const & parser, Keytype const & key, std::ostream & os) const;
+
+        PacketParserBase::size_type bytes(GenericTLVParser const & parser) const;
+        PacketParserBase::size_type bytes(GenericTLVParser const & parser, Keytype const & key) const;
+    };
+
+    struct TLVParserNotRegisteredException : public senf::Exception
+    {
+        TLVParserNotRegisteredException() : senf::Exception("tlv parser not registered") {}
+    };
+
+
+    /** \brief Statically add an entry to a TLV parser registry
+
+        This macro will declare an anonymous global variable in such a way, that constructing
+        this variable will register the given tlv parser.
+
+        \hideinitializer
+        \see senf::GenericTLVParserRegistry
+     */
+#   define SENF_PACKET_TLV_REGISTRY_REGISTER( ConreteTLVParser )                \
+        namespace {                                                             \
+            ConreteTLVParser::Registry::RegistrationProxy<ConreteTLVParser>     \
+                    BOOST_PP_CAT(tlvparserRegistration_, __LINE__);             \
+        }
+
+}
+
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 //#include "GenericTLV.cci"
 #include "GenericTLV.ct"
 #include "GenericTLV.cti"