libzypp  17.36.1
ParseDef.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <sstream>
14 #include <string>
15 #include <map>
16 
17 #include <zypp/base/Logger.h>
18 #include <zypp/base/String.h>
19 #include <utility>
20 #include <zypp-core/base/DtorReset>
21 #include <zypp-core/base/DefaultIntegral>
22 
26 #include <zypp/parser/xml/Reader.h>
27 
28 using std::endl;
29 
31 namespace zypp
32 {
33  namespace xml
35  {
36 
38  //
39  // CLASS NAME : ParseDefImplConsume
40  //
43  {
44  void start( const Node & node_r ) override
45  {
46  debuglog( "START ", node_r );
48  }
49 
50  void text( const Node & node_r ) override
51  {
52  debuglog( "TEXT ", node_r );
54  }
55 
56  void cdata( const Node & node_r ) override
57  {
58  debuglog( "CDATA ", node_r );
60  }
61 
62  void done( const Node & node_r ) override
63  {
64  debuglog( "DONE ", node_r );
66  }
67 
68  void startSubnode( const Node & node_r ) override
69  {
70  debuglog( "---> ", node_r );
72  }
73 
74  void doneSubnode( const Node & node_r ) override
75  {
76  debuglog( "<--- ", node_r );
78  }
79 
80  void debuglog( const char *const tag_r, const Node & node_r )
81  {
82  if ( ParseDef::_debug )
83  DBG << tag_r << node_r << endl;
84  }
85  };
87 
89  //
90  // CLASS NAME : ParseDef::Impl
91  //
96  {
97  friend std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj );
98  public:
99  using ImplPtr = shared_ptr<Impl>;
100  using SubNodes = std::map<std::string, ImplPtr>;
101 
102  public:
103  Impl(std::string &&name_r, Mode mode_r,
104  shared_ptr<ParseDefConsume> &&target_r =
105  shared_ptr<ParseDefConsume>())
106  : _name(std::move(name_r)), _mode(mode_r), _parent(NULL) {
107  if ( target_r )
108  _callback.setRedirect( std::move(target_r) );
109  }
110 
111  Impl(const Impl &) = default;
112  Impl(Impl &&) = delete;
113  Impl &operator=(const Impl &) = delete;
114  Impl &operator=(Impl &&) = delete;
115 
117  {
118  for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
119  {
120  it->second->_parent = NULL;
121  }
122  }
123 
124  bool isOptional() const
126 
127  bool isMandatory() const
129 
130  bool singleDef() const
132 
133  bool multiDef() const
135 
136  public:
137  void addNode( const ImplPtr & subnode_r );
138 
139  ImplPtr getNode( const std::string & name_r ) const
140  {
141  SubNodes::const_iterator it = _subnodes.find( name_r );
142  if ( it != _subnodes.end() )
143  return it->second;
144  return ImplPtr();
145  }
146 
147  void take( Reader & reader_r );
148 
149  private:
158  bool skipNode( Reader & reader_r );
159 
160  std::string exstr( const std::string & what_r, const Impl & impl_r ) const
161  {
162  std::ostringstream str;
163  str << impl_r << ": " << what_r;
164  return str.str();
165  }
166  std::string exstr( const std::string & what_r, const Impl & impl_r, const Reader & reader_r ) const
167  {
168  std::ostringstream str;
169  str << impl_r << ": " << what_r << " |reading " << *reader_r;
170  return str.str();
171  }
172 
173  public:
174  std::string _name;
177 
181 
183  };
185 
187  //
188  // METHOD NAME : ParseDef::Impl::addNode
189  // METHOD TYPE : void
190  //
191  void ParseDef::Impl::addNode( const ImplPtr & subnode_r )
192  {
193  std::pair<SubNodes::iterator, bool> res
194  = _subnodes.insert( std::make_pair( subnode_r->_name, subnode_r ) );
195 
196  if ( ! res.second )
197  {
198  ZYPP_THROW( ParseDefBuildException( exstr("Multiple definiton of subnode "+subnode_r->_name, *this) ) );
199  }
200  if ( res.first->second->_parent )
201  {
202  ZYPP_THROW( ParseDefBuildException( exstr("Can not reparent subnode "+subnode_r->_name, *this) ) );
203  }
204  res.first->second->_parent = this;
205  }
206 
208  //
209  // METHOD NAME : ParseDef::Impl::take
210  // METHOD TYPE : void
211  //
212  void ParseDef::Impl::take( Reader & reader_r )
213  {
214  if ( reader_r->nodeType() != XML_READER_TYPE_ELEMENT )
215  {
216  if ( reader_r->depth() == 0 )
217  {
218  // on the very first level we skip any initial whitespace and comments...
219  do {
220  // advance to next node
221  if ( ! reader_r.nextNode() )
222  {
223  ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
224  }
225  } while( reader_r->nodeType() != XML_READER_TYPE_ELEMENT );
226  }
227  else
228  {
229  ZYPP_THROW( ParseDefValidateException( exstr("Expected ELEMENT", *this, reader_r) ) );
230  }
231  }
232  if ( reader_r->name() != _name )
233  {
234  ZYPP_THROW( ParseDefValidateException( exstr("Wrong ELEMENT name", *this, reader_r) ) );
235  }
236  if ( _visited >= 1 && ! multiDef() )
237  {
238  ZYPP_THROW( ParseDefValidateException( exstr("Multiple definitions", *this, reader_r) ) );
239  }
240 
241  ++_visited; // Accepted to parse
242  DtorReset x( _parseDepth, -1 );
243  _parseDepth = reader_r->depth();
244 
245  // Parse attributes
246  _callback.start( *reader_r );
247 
248  // Get content up to end node
249  // Empty element (<node />) has no separate end node, so
250  // there's nothing to parse.
251  if ( ! reader_r->isEmptyElement() )
252  {
253  // For non empty elements (<node></node>) parse known nodes
254  // text and cdata elelments skip unknown nodes.
255  for ( bool done = false; ! done ; /*advance in inside loop*/)
256  {
257  // advance to next node
258  if ( ! reader_r.nextNode() )
259  {
260  ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
261  }
262 
263  switch ( reader_r->nodeType() )
264  {
265  case XML_READER_TYPE_ELEMENT:
266  // Parse or skip unknown. Anyway reader is located at the
267  // corresponding end node, or an exception was thrown.
268  {
269  ImplPtr sub( getNode( reader_r->name().asString() ) );
270  if ( sub )
271  {
272  _callback.startSubnode( *reader_r );
273  sub->take( reader_r );
274  _callback.doneSubnode( *reader_r );
275  }
276  else
277  {
278  if ( ParseDef::_debug )
279  WAR << "Skip unknown node " << *reader_r << " in "<< *this << endl;
280  skipNode( reader_r );
281  }
282  }
283  break;
284 
285  case XML_READER_TYPE_END_ELEMENT:
286  // This must be the corresponding end node!
287  if ( reader_r->depth() == _parseDepth
288  && reader_r->name() == _name )
289  {
290  done = true;
291  }
292  else
293  {
294  ZYPP_THROW( ParseDefValidateException( exstr("unexpected END_ELEMENT name", *this, reader_r) ) );
295  }
296  break;
297 
298  case XML_READER_TYPE_TEXT:
299  // collect or skip
300  _callback.text( *reader_r );
301  break;
302 
303  case XML_READER_TYPE_CDATA:
304  // collect or skip
305  _callback.cdata( *reader_r );
306  break;
307 
308  default:
309  //DBG << exstr("SKIP ", *this, reader_r) << endl;
310  break;
311  }
312  }
313  }
314 
315  // Parsing complete. Check whether all mandatory nodes were
316  // present. Finally position behind the end node.
317  for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
318  {
319  if ( ! it->second->_visited && it->second->isMandatory() )
320  {
321  ZYPP_THROW( ParseDefValidateException( exstr("Mandatory ELEMENT missing", *(it->second), reader_r) ) );
322  }
323  it->second->_visited = 0; // reset to be ready for an other visit to this!!
324  }
325 
326  _callback.done( *reader_r );
327  }
328 
330  //
331  // METHOD NAME : ParseDef::Impl::skipNode
332  // METHOD TYPE : void
333  //
335  {
336  if ( ! reader_r.seekToEndNode( reader_r->depth(),
337  reader_r->name().asString() ) )
338  {
340  ( exstr( str::form( "EOF while looking for [%d] <\\%s>",
341  reader_r->depth(),
342  reader_r->name().c_str() ),
343  *this ) ) );
344  }
345  return true;
346  }
347 
348  /******************************************************************
349  **
350  ** FUNCTION NAME : operator<<
351  ** FUNCTION TYPE : std::ostream &
352  */
353  std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj )
354  {
355  return str << "ParseDef(" << obj._name
356  << ", " << obj._mode
357  << ", visits " << obj._visited
358  << ")";
359  }
360 
362  //
363  // CLASS NAME : ParseDef
364  //
366 
367  bool ParseDef::_debug = false;
368 
370  //
371  // METHOD NAME : ParseDef::ParseDef
372  // METHOD TYPE : Ctor
373  //
374  ParseDef::ParseDef( std::string name_r, Mode mode_r )
375  : _pimpl( new Impl( std::move(name_r), mode_r ) )
376  {}
377 
378  ParseDef::ParseDef( std::string name_r, Mode mode_r, shared_ptr<ParseDefConsume> target_r )
379  : _pimpl( new Impl( std::move(name_r), mode_r, std::move(target_r) ) )
380  {}
381 
382  ParseDef::ParseDef( const shared_ptr<Impl> & pimpl_r )
383  : _pimpl( pimpl_r )
384  {}
385 
387  //
388  // METHOD NAME : ParseDef::~ParseDef
389  // METHOD TYPE : Dtor
390  //
392  {}
393 
394  const std::string & ParseDef::name() const
395  { return _pimpl->_name; }
396 
398  { return _pimpl->_mode; }
399 
400  bool ParseDef::isOptional() const
401  { return _pimpl->isOptional(); }
402 
404  { return _pimpl->isMandatory(); }
405 
406  bool ParseDef::singleDef() const
407  { return _pimpl->singleDef(); }
408 
409  bool ParseDef::multiDef() const
410  { return _pimpl->multiDef(); }
411 
412  unsigned ParseDef::visited() const
413  { return _pimpl->_visited; }
414 
416  { _pimpl->addNode( subnode_r._pimpl.getPtr() ); return *this; }
417 
418  ParseDef ParseDef::operator[]( const std::string & name_r )
419  {
420  shared_ptr<Impl> retimpl( _pimpl->getNode( name_r ) );
421  if ( ! retimpl )
422  {
423  ZYPP_THROW( ParseDefBuildException( "No subnode "+name_r ) );
424  }
425  return retimpl;
426  }
427 
428  void ParseDef::setConsumer( const shared_ptr<ParseDefConsume> & target_r )
429  { _pimpl->_callback.setRedirect( target_r ); }
430 
431  void ParseDef::setConsumer( ParseDefConsume * allocatedTarget_r )
432  { _pimpl->_callback.setRedirect( allocatedTarget_r ); }
433 
435  { _pimpl->_callback.setRedirect( target_r ); }
436 
439 
440  shared_ptr<ParseDefConsume> ParseDef::getConsumer() const
441  { return _pimpl->_callback.getRedirect(); }
442 
443 
444  void ParseDef::take( Reader & reader_r )
445  { _pimpl->take( reader_r ); }
446 
447  /******************************************************************
448  **
449  ** FUNCTION NAME : operator<<
450  ** FUNCTION TYPE : std::ostream &
451  */
452  std::ostream & operator<<( std::ostream & str, ParseDef::Mode obj )
453  {
454  switch ( obj )
455  {
456 #define X(T) case ParseDef::T: return str << #T
457  X(OPTIONAL);
458  X(MANDTAORY);
459  X(MULTIPLE_OPTIONAL);
460  X(MULTIPLE_MANDTAORY);
461 #undef X
462  }
463  return str;
464  }
465 
466  /******************************************************************
467  **
468  ** FUNCTION NAME : operator<<
469  ** FUNCTION TYPE : std::ostream &
470  */
471  std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
472  {
473  return str << obj._pimpl;
474  }
475 
477  } // namespace xml
480 } // namespace zypp
bool isMandatory() const
Definition: ParseDef.cc:127
static bool _debug
Definition: ParseDef.h:229
bool isMandatory() const
Definition: ParseDef.cc:403
std::unordered_set< sat::detail::IdType > _visited
bool multiDef() const
Definition: ParseDef.cc:409
friend std::ostream & operator<<(std::ostream &str, const ParseDef::Impl &obj)
Definition: ParseDef.cc:353
bit::BitField< ModeBitsType > ModeBits
RW_pointer< Impl > _pimpl
Pointer to implementation (shared!)
Definition: ParseDef.h:220
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
Define a xml node structure to parse.
Definition: ParseDef.h:128
Impl(std::string &&name_r, Mode mode_r, shared_ptr< ParseDefConsume > &&target_r=shared_ptr< ParseDefConsume >())
Definition: ParseDef.cc:103
NodeType nodeType() const
Get the node type of the current node.
Definition: Node.h:126
constPtrType getPtr() const
Definition: PtrTypes.h:359
bool singleDef() const
Definition: ParseDef.cc:130
String related utilities and Regular expression matching.
void start(const Node &_node) override
Definition: Arch.h:363
void text(const Node &_node) override
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
bool skipNode(Reader &reader_r)
Skip the current node.
Definition: ParseDef.cc:334
DefaultIntegral< int,-1 > _parseDepth
Definition: ParseDef.cc:182
shared_ptr< ParseDefConsume > getRedirect() const
bool nextNode()
Definition: Reader.cc:142
shared_ptr< Impl > ImplPtr
Definition: ParseDef.cc:99
Assign a vaiable a certain value when going out of scope.
Definition: dtorreset.h:49
Parse exceptions related to the documents node structure.
void cdata(const Node &_node) override
std::map< std::string, ImplPtr > SubNodes
Definition: ParseDef.cc:100
xmlTextReader based interface to Reader&#39;s current node.
Definition: Node.h:35
#define X(T)
ParseDef implementation.
Definition: ParseDef.cc:95
void startSubnode(const Node &_node) override
void take(Reader &reader_r)
Parse the node.
Definition: ParseDef.cc:444
DefaultIntegral< unsigned, 0 > _visited
Definition: ParseDef.cc:176
#define WAR
Definition: Logger.h:101
void addNode(const ImplPtr &subnode_r)
Definition: ParseDef.cc:191
void start(const Node &node_r) override
Definition: ParseDef.cc:44
void done(const Node &node_r) override
Definition: ParseDef.cc:62
Exceptions when building a ParseDef tree.
const char * c_str() const
Explicit conversion to const char *.
Definition: XmlString.h:73
void startSubnode(const Node &node_r) override
Definition: ParseDef.cc:68
bool seekToEndNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:214
Base class for ParseDef consumer.
std::string exstr(const std::string &what_r, const Impl &impl_r) const
Definition: ParseDef.cc:160
int depth() const
The depth of the node in the tree.
Definition: Node.h:62
void doneSubnode(const Node &node_r) override
Definition: ParseDef.cc:74
void take(Reader &reader_r)
Definition: ParseDef.cc:212
ParseDefImplConsume _callback
Definition: ParseDef.cc:180
void setRedirect(shared_ptr< ParseDefConsume > target_r)
shared_ptr< ParseDefConsume > getConsumer() const
Get data consumer.
Definition: ParseDef.cc:440
virtual ~ParseDef()
Definition: ParseDef.cc:391
ParseDef & addNode(ParseDef &subnode_r)
Add subnode definition.
Definition: ParseDef.cc:415
const ProcessCredentials & _callback
bool isOptional() const
Definition: ParseDef.cc:400
ImplPtr getNode(const std::string &name_r) const
Definition: ParseDef.cc:139
bool isOptional() const
Definition: ParseDef.cc:124
ParseDef consumer redirecting all events to another consumer.
void done(const Node &_node) override
Mode mode() const
Definition: ParseDef.cc:397
Impl & operator=(const Impl &)=delete
std::ostream & operator<<(std::ostream &str, const ReadState &obj)
Definition: libxmlfwd.cc:29
void cancelConsumer()
Unset data consumer.
Definition: ParseDef.cc:437
const std::string & name() const
Definition: ParseDef.cc:394
friend std::ostream & operator<<(std::ostream &str, const ParseDef &obj)
Definition: ParseDef.cc:471
std::string asString() const
Explicit conversion to std::string.
Definition: XmlString.h:77
ParseDef operator[](const std::string &name_r)
Get subnode by name.
Definition: ParseDef.cc:418
std::string exstr(const std::string &what_r, const Impl &impl_r, const Reader &reader_r) const
Definition: ParseDef.cc:166
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition: Node.h:118
void setConsumer(const shared_ptr< ParseDefConsume > &target_r)
Set data consumer.
Definition: ParseDef.cc:428
int isEmptyElement() const
Check if the current node is empty.
Definition: Node.h:101
unsigned visited() const
Definition: ParseDef.cc:412
void debuglog(const char *const tag_r, const Node &node_r)
Definition: ParseDef.cc:80
bool singleDef() const
Definition: ParseDef.cc:406
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
void cdata(const Node &node_r) override
Definition: ParseDef.cc:56
ParseDef(std::string name_r, Mode mode_r)
Definition: ParseDef.cc:374
Range of bits starting at bit _begin with length _size.
Definition: Bit.h:81
#define DBG
Definition: Logger.h:99
void doneSubnode(const Node &_node) override
xmlTextReader based interface to iterate xml streams.
Definition: Reader.h:95
void text(const Node &node_r) override
Definition: ParseDef.cc:50