libzypp 8.13.6
|
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