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 xml
00034 {
00035
00037
00038
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
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
00184
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
00205
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
00214 do {
00215
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;
00237 DtorReset x( _parseDepth, -1 );
00238 _parseDepth = reader_r->depth();
00239
00240
00241 _callback.start( *reader_r );
00242
00243
00244
00245
00246 if ( ! reader_r->isEmptyElement() )
00247 {
00248
00249
00250 for ( bool done = false; ! done ; )
00251 {
00252
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
00262
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
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
00295 _callback.text( *reader_r );
00296 break;
00297
00298 case XML_READER_TYPE_CDATA:
00299
00300 _callback.cdata( *reader_r );
00301 break;
00302
00303 default:
00304
00305 break;
00306 }
00307 }
00308 }
00309
00310
00311
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;
00319 }
00320
00321 _callback.done( *reader_r );
00322 }
00323
00325
00326
00327
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
00346
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
00359
00361
00362 bool ParseDef::_debug = false;
00363
00365
00366
00367
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
00384
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
00445
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
00464
00465
00466 std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
00467 {
00468 return str << obj._pimpl;
00469 }
00470
00472 }
00475 }