libzypp  10.5.0
ParseDef.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 #include <string>
00015 #include <map>
00016 
00017 #include "zypp/base/Logger.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/DtorReset.h"
00020 #include "zypp/base/DefaultIntegral.h"
00021 
00022 #include "zypp/parser/xml/ParseDef.h"
00023 #include "zypp/parser/xml/ParseDefException.h"
00024 #include "zypp/parser/xml/ParseDefConsume.h"
00025 #include "zypp/parser/xml/Reader.h"
00026 
00027 using std::endl;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace xml
00034   { 
00035 
00037     //
00038     //  CLASS NAME : ParseDefImplConsume
00039     //
00041     struct ParseDefImplConsume : public ParseDefConsumeRedirect
00042     {
00043       virtual void start( const Node & node_r )
00044       {
00045         debuglog( "START ", node_r );
00046         ParseDefConsumeRedirect::start( node_r );
00047       }
00048 
00049       virtual void text( const Node & node_r )
00050       {
00051         debuglog( "TEXT  ", node_r );
00052         ParseDefConsumeRedirect::text( node_r );
00053       }
00054 
00055       virtual void cdata( const Node & node_r )
00056       {
00057         debuglog( "CDATA ", node_r );
00058         ParseDefConsumeRedirect::cdata( node_r );
00059       }
00060 
00061       virtual void done( const Node & node_r )
00062       {
00063         debuglog( "DONE  ", node_r );
00064         ParseDefConsumeRedirect::done( node_r );
00065       }
00066 
00067       virtual void startSubnode( const Node & node_r )
00068       {
00069         debuglog( "--->  ", node_r );
00070         ParseDefConsumeRedirect::startSubnode( node_r );
00071       }
00072 
00073       virtual void doneSubnode( const Node & node_r )
00074       {
00075         debuglog( "<---  ", node_r );
00076         ParseDefConsumeRedirect::doneSubnode( node_r );
00077       }
00078 
00079       void debuglog( const char *const tag_r, const Node & node_r )
00080       {
00081         if ( ParseDef::_debug )
00082           DBG << tag_r << node_r << endl;
00083       }
00084     };
00086 
00088     //
00089     //  CLASS NAME : ParseDef::Impl
00090     //
00094     class ParseDef::Impl
00095     {
00096       friend std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj );
00097     public:
00098       typedef shared_ptr<Impl>               ImplPtr;
00099       typedef std::map<std::string, ImplPtr> SubNodes;
00100 
00101     public:
00102       Impl( const std::string & name_r, Mode mode_r, const shared_ptr<ParseDefConsume> & target_r = shared_ptr<ParseDefConsume>() )
00103       : _name( name_r )
00104       , _mode( mode_r )
00105       , _parent( NULL )
00106       {
00107         if ( target_r )
00108           _callback.setRedirect( target_r );
00109       }
00110 
00111       ~Impl()
00112       {
00113         for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00114           {
00115             it->second->_parent = NULL;
00116           }
00117       }
00118 
00119       bool isOptional() const
00120       { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_OPTIONAL ); }
00121 
00122       bool isMandatory() const
00123       { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_MANDTAORY ); }
00124 
00125       bool singleDef() const
00126       { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_ONCE ); }
00127 
00128       bool multiDef() const
00129       { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_MULTIPLE ); }
00130 
00131     public:
00132       void addNode( const ImplPtr & subnode_r );
00133 
00134       ImplPtr getNode( const std::string & name_r ) const
00135       {
00136         SubNodes::const_iterator it = _subnodes.find( name_r );
00137         if ( it != _subnodes.end() )
00138           return it->second;
00139         return ImplPtr();
00140       }
00141 
00142       void take( Reader & reader_r );
00143 
00144     private:
00153       bool skipNode( Reader & reader_r );
00154 
00155       std::string exstr( const std::string & what_r, const Impl & impl_r ) const
00156       {
00157         std::ostringstream str;
00158         str << impl_r << ": " << what_r;
00159         return str.str();
00160       }
00161       std::string exstr( const std::string & what_r, const Impl & impl_r, const Reader & reader_r ) const
00162       {
00163         std::ostringstream str;
00164         str << impl_r << ": " << what_r << " |reading " << *reader_r;
00165         return str.str();
00166       }
00167 
00168     public:
00169       std::string                 _name;
00170       Mode                        _mode;
00171       DefaultIntegral<unsigned,0> _visited;
00172 
00173       Impl *                      _parent;
00174       SubNodes                    _subnodes;
00175       ParseDefImplConsume         _callback;
00176 
00177       DefaultIntegral<int,-1>     _parseDepth;
00178     };
00180 
00182     //
00183     //  METHOD NAME : ParseDef::Impl::addNode
00184     //  METHOD TYPE : void
00185     //
00186     void ParseDef::Impl::addNode( const ImplPtr & subnode_r )
00187     {
00188       std::pair<SubNodes::iterator, bool> res
00189       = _subnodes.insert( std::make_pair( subnode_r->_name, subnode_r ) );
00190 
00191       if ( ! res.second )
00192         {
00193           ZYPP_THROW( ParseDefBuildException( exstr("Multiple definiton of subnode "+subnode_r->_name, *this) ) );
00194         }
00195       if ( res.first->second->_parent )
00196         {
00197           ZYPP_THROW( ParseDefBuildException( exstr("Can not reparent subnode "+subnode_r->_name, *this) ) );
00198         }
00199       res.first->second->_parent = this;
00200     }
00201 
00203     //
00204     //  METHOD NAME : ParseDef::Impl::take
00205     //  METHOD TYPE : void
00206     //
00207     void ParseDef::Impl::take( Reader & reader_r )
00208     {
00209       if ( reader_r->nodeType() != XML_READER_TYPE_ELEMENT )
00210         {
00211           if ( reader_r->depth() == 0 )
00212           {
00213             // on the verry first level we skip any initial whitespace and comments...
00214             do {
00215               // advance to next node
00216               if ( ! reader_r.nextNode() )
00217                 {
00218                   ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
00219                 }
00220             } while( reader_r->nodeType() != XML_READER_TYPE_ELEMENT );
00221           }
00222           else
00223           {
00224             ZYPP_THROW( ParseDefValidateException( exstr("Expected ELEMENT", *this, reader_r) ) );
00225           }
00226         }
00227       if ( reader_r->name() != _name )
00228         {
00229           ZYPP_THROW( ParseDefValidateException( exstr("Wrong ELEMENT name", *this, reader_r) ) );
00230         }
00231       if ( _visited >= 1 && ! multiDef() )
00232         {
00233           ZYPP_THROW( ParseDefValidateException( exstr("Multiple definitions", *this, reader_r) ) );
00234         }
00235 
00236       ++_visited; // Accepted to parse
00237       DtorReset x( _parseDepth, -1 );
00238       _parseDepth = reader_r->depth();
00239 
00240       // Parse attributes
00241       _callback.start( *reader_r );
00242 
00243       // Get content up to end node
00244       // Empty element (<node />) has no separate end node, so
00245       // there's nothing to parse.
00246       if ( ! reader_r->isEmptyElement() )
00247         {
00248           // For non empty elements (<node></node>) parse known nodes
00249           // text and cdata elelments skip unknown nodes.
00250           for ( bool done = false; ! done ; /*advance in inside loop*/)
00251             {
00252               // advance to next node
00253               if ( ! reader_r.nextNode() )
00254                 {
00255                   ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
00256                 }
00257 
00258               switch ( reader_r->nodeType() )
00259                 {
00260                 case XML_READER_TYPE_ELEMENT:
00261                   // Parse or skip unknown. Anyway reader is located at the
00262                   // corresponding end node, or an exception was thrown.
00263                   {
00264                     ImplPtr sub( getNode( reader_r->name().asString() ) );
00265                     if ( sub )
00266                       {
00267                         _callback.startSubnode( *reader_r );
00268                         sub->take( reader_r );
00269                         _callback.doneSubnode( *reader_r );
00270                       }
00271                     else
00272                       {
00273                         if ( ParseDef::_debug )
00274                           WAR << "Skip unknown node " << *reader_r << " in "<< *this << endl;
00275                         skipNode( reader_r );
00276                       }
00277                   }
00278                 break;
00279 
00280                 case XML_READER_TYPE_END_ELEMENT:
00281                   // This must be the corresponding end node!
00282                   if ( reader_r->depth() == _parseDepth
00283                        && reader_r->name() == _name )
00284                     {
00285                       done = true;
00286                     }
00287                   else
00288                     {
00289                       ZYPP_THROW( ParseDefValidateException( exstr("unexpected END_ELEMENT name", *this, reader_r) ) );
00290                     }
00291                   break;
00292 
00293                 case XML_READER_TYPE_TEXT:
00294                   // collect or skip
00295                   _callback.text( *reader_r );
00296                   break;
00297 
00298                 case XML_READER_TYPE_CDATA:
00299                   // collect or skip
00300                   _callback.cdata( *reader_r );
00301                   break;
00302 
00303                 default:
00304                   //DBG << exstr("SKIP ", *this, reader_r) << endl;
00305                   break;
00306                 }
00307             }
00308         }
00309 
00310       // Parsing complete. Check whether all mandatory nodes were
00311       // present. Finally position behind the end node.
00312       for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00313         {
00314           if ( ! it->second->_visited && it->second->isMandatory() )
00315             {
00316               ZYPP_THROW( ParseDefValidateException( exstr("Mandatory ELEMENT missing", *(it->second), reader_r) ) );
00317             }
00318           it->second->_visited = 0; // reset to be ready for an other visit to this!!
00319         }
00320 
00321       _callback.done( *reader_r );
00322     }
00323 
00325     //
00326     //  METHOD NAME : ParseDef::Impl::skipNode
00327     //  METHOD TYPE : void
00328     //
00329     bool ParseDef::Impl::skipNode( xml::Reader & reader_r )
00330     {
00331       if ( ! reader_r.seekToEndNode( reader_r->depth(),
00332                                      reader_r->name().asString() ) )
00333         {
00334           ZYPP_THROW( ParseDefValidateException
00335                       ( exstr( str::form( "EOF while looking for [%d] <\\%s>",
00336                                           reader_r->depth(),
00337                                           reader_r->name().c_str() ),
00338                                *this ) ) );
00339         }
00340       return true;
00341     }
00342 
00343     /******************************************************************
00344      **
00345      ** FUNCTION NAME : operator<<
00346      ** FUNCTION TYPE : std::ostream &
00347     */
00348     std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj )
00349     {
00350       return str << "ParseDef(" << obj._name
00351                  << ", " << obj._mode
00352                  << ", visits " << obj._visited
00353                  << ")";
00354     }
00355 
00357     //
00358     //  CLASS NAME : ParseDef
00359     //
00361 
00362     bool ParseDef::_debug = false;
00363 
00365     //
00366     //  METHOD NAME : ParseDef::ParseDef
00367     //  METHOD TYPE : Ctor
00368     //
00369     ParseDef::ParseDef( const std::string & name_r, Mode mode_r )
00370     : _pimpl( new Impl( name_r, mode_r ) )
00371     {}
00372 
00373     ParseDef::ParseDef( const std::string & name_r, Mode mode_r, const shared_ptr<ParseDefConsume> & target_r )
00374     : _pimpl( new Impl( name_r, mode_r, target_r ) )
00375     {}
00376 
00377     ParseDef::ParseDef( const shared_ptr<Impl> & pimpl_r )
00378     : _pimpl( pimpl_r )
00379     {}
00380 
00382     //
00383     //  METHOD NAME : ParseDef::~ParseDef
00384     //  METHOD TYPE : Dtor
00385     //
00386     ParseDef::~ParseDef()
00387     {}
00388 
00389     const std::string & ParseDef::name() const
00390     { return _pimpl->_name; }
00391 
00392     ParseDef::Mode ParseDef::mode() const
00393     { return _pimpl->_mode; }
00394 
00395     bool ParseDef::isOptional() const
00396     { return _pimpl->isOptional(); }
00397 
00398     bool ParseDef::isMandatory() const
00399     { return _pimpl->isMandatory(); }
00400 
00401     bool ParseDef::singleDef() const
00402     { return _pimpl->singleDef(); }
00403 
00404     bool ParseDef::multiDef() const
00405     { return _pimpl->multiDef(); }
00406 
00407     unsigned ParseDef::visited() const
00408     { return _pimpl->_visited; }
00409 
00410     ParseDef & ParseDef::addNode( ParseDef & subnode_r )
00411     { _pimpl->addNode( subnode_r._pimpl.getPtr() ); return *this; }
00412 
00413     ParseDef ParseDef::operator[]( const std::string & name_r )
00414     {
00415       shared_ptr<Impl> retimpl( _pimpl->getNode( name_r ) );
00416       if ( ! retimpl )
00417         {
00418           ZYPP_THROW( ParseDefBuildException( "No subnode "+name_r ) );
00419         }
00420       return retimpl;
00421     }
00422 
00423     void ParseDef::setConsumer( const shared_ptr<ParseDefConsume> & target_r )
00424     { _pimpl->_callback.setRedirect( target_r ); }
00425 
00426     void ParseDef::setConsumer( ParseDefConsume * allocatedTarget_r )
00427     { _pimpl->_callback.setRedirect( allocatedTarget_r ); }
00428 
00429     void ParseDef::setConsumer( ParseDefConsume & target_r )
00430     { _pimpl->_callback.setRedirect( target_r ); }
00431 
00432     void ParseDef::cancelConsumer()
00433     { _pimpl->_callback.cancelRedirect(); }
00434 
00435     shared_ptr<ParseDefConsume> ParseDef::getConsumer() const
00436     { return _pimpl->_callback.getRedirect(); }
00437 
00438 
00439     void ParseDef::take( Reader & reader_r )
00440     { _pimpl->take( reader_r ); }
00441 
00442     /******************************************************************
00443      **
00444      ** FUNCTION NAME : operator<<
00445      ** FUNCTION TYPE : std::ostream &
00446     */
00447     std::ostream & operator<<( std::ostream & str, ParseDef::Mode obj )
00448     {
00449       switch ( obj )
00450         {
00451 #define X(T) case ParseDef::T: return str << #T
00452           X(OPTIONAL);
00453           X(MANDTAORY);
00454           X(MULTIPLE_OPTIONAL);
00455           X(MULTIPLE_MANDTAORY);
00456 #undef X
00457         }
00458       return str;
00459     }
00460 
00461     /******************************************************************
00462      **
00463      ** FUNCTION NAME : operator<<
00464      ** FUNCTION TYPE : std::ostream &
00465     */
00466     std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
00467     {
00468       return str << obj._pimpl;
00469     }
00470 
00472   } // namespace xml
00475 } // namespace zypp