00001
00002
00003
00004
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 debug
00034 {
00035
00036 template<class _Derived>
00037 struct TraceInstance
00038 {
00039 TraceInstance()
00040 { total(1); }
00041 TraceInstance( const TraceInstance & rhs )
00042 { total(1); }
00043 ~TraceInstance()
00044 { total(-1); }
00045 static unsigned & total( int cnt_r )
00046 {
00047 static unsigned _total = 0;
00048 _total += cnt_r;
00049 INT << "total += " << cnt_r << " => " << _total << endl;
00050 return _total;
00051 }
00052 };
00053
00055 }
00058 }
00060
00061
00063 namespace zypp
00064 {
00065
00066 namespace xml
00067 {
00068
00070
00071
00072
00074 struct ParseDefImplConsume : public ParseDefConsumeRedirect
00075 {
00076 virtual void start( const Node & node_r )
00077 {
00078 debuglog( "START ", node_r );
00079 ParseDefConsumeRedirect::start( node_r );
00080 }
00081
00082 virtual void text( const Node & node_r )
00083 {
00084 debuglog( "TEXT ", node_r );
00085 ParseDefConsumeRedirect::text( node_r );
00086 }
00087
00088 virtual void cdata( const Node & node_r )
00089 {
00090 debuglog( "CDATA ", node_r );
00091 ParseDefConsumeRedirect::cdata( node_r );
00092 }
00093
00094 virtual void done( const Node & node_r )
00095 {
00096 debuglog( "DONE ", node_r );
00097 ParseDefConsumeRedirect::done( node_r );
00098 }
00099
00100 virtual void startSubnode( const Node & node_r )
00101 {
00102 debuglog( "---> ", node_r );
00103 ParseDefConsumeRedirect::start( node_r );
00104 }
00105
00106 virtual void doneSubnode( const Node & node_r )
00107 {
00108 debuglog( "<--- ", node_r );
00109 ParseDefConsumeRedirect::done( node_r );
00110 }
00111
00112 void debuglog( const char *const tag_r, const Node & node_r )
00113 {
00114 if ( ParseDef::_debug )
00115 DBG << tag_r << node_r << endl;
00116 }
00117 };
00119
00121
00122
00123
00127 class ParseDef::Impl
00128 {
00129 friend std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj );
00130 public:
00131 typedef shared_ptr<Impl> ImplPtr;
00132 typedef std::map<std::string, ImplPtr> SubNodes;
00133
00134 public:
00135 Impl( const std::string & name_r, Mode mode_r )
00136 : _name( name_r )
00137 , _mode( mode_r )
00138 , _parent( NULL )
00139 {}
00140
00141 ~Impl()
00142 {
00143 for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00144 {
00145 it->second->_parent = NULL;
00146 }
00147 }
00148
00149 bool isOptional() const
00150 { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_OPTIONAL ); }
00151
00152 bool isMandatory() const
00153 { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_MANDTAORY ); }
00154
00155 bool singleDef() const
00156 { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_ONCE ); }
00157
00158 bool multiDef() const
00159 { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_MULTIPLE ); }
00160
00161 public:
00162 void addNode( const ImplPtr & subnode_r );
00163
00164 ImplPtr getNode( const std::string & name_r ) const
00165 {
00166 SubNodes::const_iterator it = _subnodes.find( name_r );
00167 if ( it != _subnodes.end() )
00168 return it->second;
00169 return ImplPtr();
00170 }
00171
00172 void take( Reader & reader_r );
00173
00174 private:
00183 bool skipNode( Reader & reader_r );
00184
00185 std::string exstr( const std::string & what_r, const Impl & impl_r ) const
00186 {
00187 std::ostringstream str;
00188 str << impl_r << ": " << what_r;
00189 return str.str();
00190 }
00191 std::string exstr( const std::string & what_r, const Impl & impl_r, const Reader & reader_r ) const
00192 {
00193 std::ostringstream str;
00194 str << impl_r << ": " << what_r << " |reading " << *reader_r;
00195 return str.str();
00196 }
00197
00198 public:
00199 std::string _name;
00200 Mode _mode;
00201 DefaultIntegral<unsigned,0> _visited;
00202
00203 Impl * _parent;
00204 SubNodes _subnodes;
00205 ParseDefImplConsume _callback;
00206
00207 DefaultIntegral<int,-1> _parseDepth;
00208 };
00210
00212
00213
00214
00215
00216 void ParseDef::Impl::addNode( const ImplPtr & subnode_r )
00217 {
00218 std::pair<SubNodes::iterator, bool> res
00219 = _subnodes.insert( std::make_pair( subnode_r->_name, subnode_r ) );
00220
00221 if ( ! res.second )
00222 {
00223 ZYPP_THROW( ParseDefBuildException( exstr("Multiple definiton of subnode "+subnode_r->_name, *this) ) );
00224 }
00225 if ( res.first->second->_parent )
00226 {
00227 ZYPP_THROW( ParseDefBuildException( exstr("Can not reparent subnode "+subnode_r->_name, *this) ) );
00228 }
00229 res.first->second->_parent = this;
00230 }
00231
00233
00234
00235
00236
00237 void ParseDef::Impl::take( Reader & reader_r )
00238 {
00239 if ( reader_r->nodeType() != XML_READER_TYPE_ELEMENT )
00240 {
00241 ZYPP_THROW( ParseDefValidateException( exstr("Expected ELEMENT", *this, reader_r) ) );
00242 }
00243 if ( reader_r->name() != _name )
00244 {
00245 ZYPP_THROW( ParseDefValidateException( exstr("Wrong ELEMENT name", *this, reader_r) ) );
00246 }
00247 if ( _visited >= 1 && ! multiDef() )
00248 {
00249 ZYPP_THROW( ParseDefValidateException( exstr("Multiple definitions", *this, reader_r) ) );
00250 }
00251
00252 ++_visited;
00253 DtorReset x( _parseDepth, -1 );
00254 _parseDepth = reader_r->depth();
00255
00256
00257 _callback.start( *reader_r );
00258
00259
00260
00261
00262 if ( ! reader_r->isEmptyElement() )
00263 {
00264
00265
00266 for ( bool done = false; ! done ; )
00267 {
00268
00269 if ( ! reader_r.nextNode() )
00270 {
00271 ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
00272 }
00273
00274 switch ( reader_r->nodeType() )
00275 {
00276 case XML_READER_TYPE_ELEMENT:
00277
00278
00279 {
00280 ImplPtr sub( getNode( reader_r->name().asString() ) );
00281 if ( sub )
00282 {
00283 _callback.startSubnode( *reader_r );
00284 sub->take( reader_r );
00285 _callback.doneSubnode( *reader_r );
00286 }
00287 else
00288 {
00289 WAR << "Skip unknown node " << *reader_r << " in "<< *this << endl;
00290 skipNode( reader_r );
00291 }
00292 }
00293 break;
00294
00295 case XML_READER_TYPE_END_ELEMENT:
00296
00297 if ( reader_r->depth() == _parseDepth
00298 && reader_r->name() == _name )
00299 {
00300 done = true;
00301 }
00302 else
00303 {
00304 ZYPP_THROW( ParseDefValidateException( exstr("unexpected END_ELEMENT name", *this, reader_r) ) );
00305 }
00306 break;
00307
00308 case XML_READER_TYPE_TEXT:
00309
00310 _callback.text( *reader_r );
00311 break;
00312
00313 case XML_READER_TYPE_CDATA:
00314
00315 _callback.cdata( *reader_r );
00316 break;
00317
00318 default:
00319 break;
00320 }
00321 }
00322 }
00323
00324
00325
00326 for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00327 {
00328 if ( ! it->second->_visited && it->second->isMandatory() )
00329 {
00330 ZYPP_THROW( ParseDefValidateException( exstr("Mandatory ELEMENT missing", *(it->second), reader_r) ) );
00331 }
00332 it->second->_visited = 0;
00333 }
00334
00335 _callback.done( *reader_r );
00336 }
00337
00339
00340
00341
00342
00343 bool ParseDef::Impl::skipNode( xml::Reader & reader_r )
00344 {
00345 if ( ! reader_r.seekToEndNode( reader_r->depth(),
00346 reader_r->name().asString() ) )
00347 {
00348 ZYPP_THROW( ParseDefValidateException
00349 ( exstr( str::form( "EOF while looking for [%d] <\\%s>",
00350 reader_r->depth(),
00351 reader_r->name().c_str() ),
00352 *this ) ) );
00353 }
00354 return true;
00355 }
00356
00357
00358
00359
00360
00361
00362 std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj )
00363 {
00364 return str << "ParseDef(" << obj._name
00365 << ", " << obj._mode
00366 << ", visits " << obj._visited
00367 << ")";
00368 }
00369
00371
00372
00373
00375
00376 bool ParseDef::_debug = false;
00377
00379
00380
00381
00382
00383 ParseDef::ParseDef( const std::string & name_r, Mode mode_r )
00384 : _pimpl( new Impl( name_r, mode_r ) )
00385 {}
00386
00387 ParseDef::ParseDef( const shared_ptr<Impl> & pimpl_r )
00388 : _pimpl( pimpl_r )
00389 {}
00390
00392
00393
00394
00395
00396 ParseDef::~ParseDef()
00397 {}
00398
00399 const std::string & ParseDef::name() const
00400 { return _pimpl->_name; }
00401
00402 ParseDef::Mode ParseDef::mode() const
00403 { return _pimpl->_mode; }
00404
00405 bool ParseDef::isOptional() const
00406 { return _pimpl->isOptional(); }
00407
00408 bool ParseDef::isMandatory() const
00409 { return _pimpl->isMandatory(); }
00410
00411 bool ParseDef::singleDef() const
00412 { return _pimpl->singleDef(); }
00413
00414 bool ParseDef::multiDef() const
00415 { return _pimpl->multiDef(); }
00416
00417 unsigned ParseDef::visited() const
00418 { return _pimpl->_visited; }
00419
00420 ParseDef & ParseDef::addNode( ParseDef & subnode_r )
00421 { _pimpl->addNode( subnode_r._pimpl.getPtr() ); return *this; }
00422
00423 ParseDef ParseDef::operator[]( const std::string & name_r )
00424 {
00425 shared_ptr<Impl> retimpl( _pimpl->getNode( name_r ) );
00426 if ( ! retimpl )
00427 {
00428 ZYPP_THROW( ParseDefBuildException( "No subnode "+name_r ) );
00429 }
00430 return retimpl;
00431 }
00432
00433 void ParseDef::setConsumer( const shared_ptr<ParseDefConsume> & target_r )
00434 { _pimpl->_callback.setRedirect( target_r ); }
00435
00436 void ParseDef::setConsumer( ParseDefConsume * allocatedTarget_r )
00437 { _pimpl->_callback.setRedirect( allocatedTarget_r ); }
00438
00439 void ParseDef::setConsumer( ParseDefConsume & target_r )
00440 { _pimpl->_callback.setRedirect( target_r ); }
00441
00442 void ParseDef::cancelConsumer()
00443 { _pimpl->_callback.cancelRedirect(); }
00444
00445 shared_ptr<ParseDefConsume> ParseDef::getConsumer() const
00446 { return _pimpl->_callback.getRedirect(); }
00447
00448
00449 void ParseDef::take( Reader & reader_r )
00450 { _pimpl->take( reader_r ); }
00451
00452
00453
00454
00455
00456
00457 std::ostream & operator<<( std::ostream & str, ParseDef::Mode obj )
00458 {
00459 switch ( obj )
00460 {
00461 #define X(T) case ParseDef::T: return str << #T
00462 X(OPTIONAL);
00463 X(MANDTAORY);
00464 X(MULTIPLE_OPTIONAL);
00465 X(MULTIPLE_MANDTAORY);
00466 #undef X
00467 }
00468 return str;
00469 }
00470
00471
00472
00473
00474
00475
00476 std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
00477 {
00478 return str << obj._pimpl;
00479 }
00480
00482 }
00485 }