libzypp  17.31.31
Reader.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <libxml/xmlreader.h>
13 #include <libxml/xmlerror.h>
14 
15 #include <iostream>
16 
17 #include <zypp/base/LogControl.h>
18 #include <zypp/base/LogTools.h>
19 #include <zypp/base/Exception.h>
20 #include <zypp/base/String.h>
21 
22 #include <zypp/parser/xml/Reader.h>
23 
24 using std::endl;
25 
27 namespace zypp
28 {
29  namespace xml
31  {
32 
34  namespace
35  {
36 
37  int ioread( void * context_r, char * buffer_r, int bufferLen_r )
38  {
39  if ( context_r && buffer_r )
40  {
41  return reinterpret_cast<InputStream *>(context_r)
42  ->stream().read( buffer_r, bufferLen_r ).gcount();
43  }
44  INT << "XML parser error: null pointer check failed " << context_r << ' ' << (void *)buffer_r << endl;
45  return -1;
46  }
47 
48  int ioclose( void * /*context_r*/ )
49  { return 0; }
50 
51 
52  std::list<std::string> structuredErrors;
53 #if LIBXML_VERSION >= 21200
54  void structuredErrorFunc( void * userData, const xmlError * error )
55 #else
56  void structuredErrorFunc( void * userData, xmlError * error )
57 #endif
58  {
59  if ( error )
60  {
61  // error->message is NL terminated
62  std::string err( str::form( "%s[%d] %s", Pathname::basename(error->file).c_str(), error->line,
63  str::stripSuffix( error->message, "\n" ).c_str() ) );
64  structuredErrors.push_back( err );
65  WAR << err << endl;
66  }
67  }
68 
69  struct ParseException : public Exception
70  {
71  ParseException()
72  : Exception( "Parse error: " + ( structuredErrors.empty() ? std::string("unknown error"): structuredErrors.back() ) )
73  {
74  for_( it, structuredErrors.begin(), --structuredErrors.end() )
75  addHistory( *it );
76  }
77  };
78 
80  } // namespace
82 
84  //
85  // METHOD NAME : Reader::Reader
86  // METHOD TYPE : Constructor
87  //
88  Reader::Reader( const InputStream & stream_r,
89  const Validate & validate_r )
90  : _stream( stream_r )
91  , _reader( xmlReaderForIO( ioread, ioclose, &_stream,
92  stream_r.path().asString().c_str(), "utf-8", XML_PARSE_PEDANTIC ) )
93  , _node( _reader )
94  {
95  MIL << "Start Parsing " << _stream << endl;
96  if ( ! _reader || ! stream_r.stream().good() )
97  ZYPP_THROW( Exception( "Bad input stream" ) );
98  // set error handler
99  // TODO: Fix using a global lastStructuredError string is not reentrant.
100  structuredErrors.clear();
101  xmlTextReaderSetStructuredErrorHandler( _reader, structuredErrorFunc, NULL );
102  // TODO: set validation
103 
104  // advance to 1st node
105  nextNode();
106  }
107 
109  //
110  // METHOD NAME : Reader::~Reader
111  // METHOD TYPE : Destructor
112  //
114  {
115  if ( _reader )
116  {
117  xmlFreeTextReader( _reader );
118  }
119  MIL << "Done Parsing " << _stream << endl;
120  }
121 
123  {
124  if ( ! _node.isEmptyElement() )
125  {
126  if ( nextNode() )
127  {
128  if ( _node.nodeType() == XML_READER_TYPE_TEXT )
129  {
130  return _node.value();
131  }
132  }
133  }
134  return XmlString();
135  }
136 
138  //
139  // METHOD NAME : Reader::nextNode
140  // METHOD TYPE : bool
141  //
143  {
144  int ret = xmlTextReaderRead( _reader );
145  if ( ret == 1 )
146  {
147  return true;
148  }
149  xmlTextReaderClose( _reader );
150  if ( ret != 0 )
151  {
152  ZYPP_THROW( ParseException() );
153  }
154  return false;
155  }
156 
158  //
159  // METHOD NAME : Reader::nextNodeAttribute
160  // METHOD TYPE : bool
161  //
163  {
164  int ret = xmlTextReaderMoveToNextAttribute( _reader );
165  if ( ret == 1 )
166  {
167  return true;
168  }
169  if ( ret != 0 )
170  {
171  ZYPP_THROW( ParseException() );
172  }
173  return false;
174  }
175 
177  //
178  // METHOD NAME : Reader::close
179  // METHOD TYPE : void
180  //
182  {
183  if ( _reader )
184  {
185  xmlTextReaderClose( _reader );
186  }
187  }
188 
190  //
191  // METHOD NAME : Reader::seekToNode
192  // METHOD TYPE : bool
193  //
194  bool Reader::seekToNode( int depth_r, const std::string & name_r )
195  {
196  do
197  {
198  if ( _node.depth() == depth_r
199  && _node.name() == name_r
200  && _node.nodeType() == XML_READER_TYPE_ELEMENT )
201  {
202  break;
203  }
204  } while( nextNode() );
205 
206  return ! atEnd();
207  }
208 
210  //
211  // METHOD NAME : Reader::seekToEndNode
212  // METHOD TYPE : bool
213  //
214  bool Reader::seekToEndNode( int depth_r, const std::string & name_r )
215  {
216  // Empty element has no separate end node: <node/>
217  do
218  {
219  if ( _node.depth() == depth_r
220  && _node.name() == name_r
221  && ( _node.nodeType() == XML_READER_TYPE_END_ELEMENT
222  || ( _node.nodeType() == XML_READER_TYPE_ELEMENT
223  && _node.isEmptyElement() ) ) )
224  {
225  break;
226  }
227  } while( nextNode() );
228 
229  return ! atEnd();
230  }
231 
233  } // namespace xml
236 } // namespace zypp
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
#define MIL
Definition: Logger.h:96
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
Reader(const InputStream &stream_r, const Validate &validate_r=Validate::none())
Ctor.
Definition: Reader.cc:88
NodeType nodeType() const
Get the node type of the current node.
Definition: Node.h:126
XmlString value() const
Provides the text value of the node if present.
Definition: Node.h:143
#define INT
Definition: Logger.h:100
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
std::string stripSuffix(const C_Str &str_r, const C_Str &suffix_r)
Strip a suffix_r from str_r and return the resulting string.
Definition: String.h:1048
xmlChar * wrapper.
Definition: XmlString.h:40
Definition: Arch.h:363
Helper to create and pass std::istream.
Definition: inputstream.h:56
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
bool nextNode()
Definition: Reader.cc:142
bool seekToNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:194
xmlTextReaderPtr _reader
Definition: Reader.h:192
#define WAR
Definition: Logger.h:97
bool seekToEndNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:214
InputStream _stream
Definition: Reader.h:191
int depth() const
The depth of the node in the tree.
Definition: Node.h:62
xmlTextReader document validation.
Definition: Reader.h:37
bool atEnd() const
Definition: Reader.h:128
bool nextNodeAttribute()
Definition: Reader.cc:162
Base class for Exception.
Definition: Exception.h:145
XmlString nodeText()
If the current node is not empty, advances the reader to the next node, and returns the value...
Definition: Reader.cc:122
std::istream & stream() const
The std::istream.
Definition: inputstream.h:93
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition: Node.h:118
~Reader()
Dtor.
Definition: Reader.cc:113
int isEmptyElement() const
Check if the current node is empty.
Definition: Node.h:101
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1