libzypp  17.12.0
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  void structuredErrorFunc( void * userData, xmlErrorPtr error )
54  {
55  if ( error )
56  {
57  // error->message is NL terminated
58  std::string err( str::form( "%s[%d] %s", Pathname::basename(error->file).c_str(), error->line,
59  str::stripSuffix( error->message, "\n" ).c_str() ) );
60  structuredErrors.push_back( err );
61  WAR << err << endl;
62  }
63 #if 0
64  if ( error )
65  {
66 #define X(m) SEC << " " << #m << "\t" << error->m << endl
67 #define XS(m) SEC << " " << #m << "\t" << (error->m?error->m:"NA") << endl
68  X(domain);
69  X(code);
70  XS(message);
71  X(level);
72  XS(file);
73  X(line);
74  XS(str1);
75  XS(str2);
76  XS(str3);
77  X(int1);
78  X(int2);
79  X(ctxt);
80  X(node);
81 #undef X
82 #undef XS
83  }
84 #endif
85  }
86 
87  struct ParseException : public Exception
88  {
89  ParseException()
90  : Exception( "Parse error: " + ( structuredErrors.empty() ? std::string("unknown error"): structuredErrors.back() ) )
91  {
92  for_( it, structuredErrors.begin(), --structuredErrors.end() )
93  addHistory( *it );
94  }
95  };
96 
98  } // namespace
100 
102  //
103  // METHOD NAME : Reader::Reader
104  // METHOD TYPE : Constructor
105  //
106  Reader::Reader( const InputStream & stream_r,
107  const Validate & validate_r )
108  : _stream( stream_r )
109  , _reader( xmlReaderForIO( ioread, ioclose, &_stream,
110  stream_r.path().asString().c_str(), "utf-8", XML_PARSE_PEDANTIC ) )
111  , _node( _reader )
112  {
113  MIL << "Start Parsing " << _stream << endl;
114  if ( ! _reader || ! stream_r.stream().good() )
115  ZYPP_THROW( Exception( "Bad input stream" ) );
116  // set error handler
117  // TODO: Fix using a global lastStructuredError string is not reentrant.
118  structuredErrors.clear();
119  xmlTextReaderSetStructuredErrorHandler( _reader, structuredErrorFunc, NULL );
120  // TODO: set validation
121 
122  // advance to 1st node
123  nextNode();
124  }
125 
127  //
128  // METHOD NAME : Reader::~Reader
129  // METHOD TYPE : Destructor
130  //
132  {
133  if ( _reader )
134  {
135  xmlFreeTextReader( _reader );
136  }
137  MIL << "Done Parsing " << _stream << endl;
138  }
139 
141  {
142  if ( ! _node.isEmptyElement() )
143  {
144  if ( nextNode() )
145  {
146  if ( _node.nodeType() == XML_READER_TYPE_TEXT )
147  {
148  return _node.value();
149  }
150  }
151  }
152  return XmlString();
153  }
154 
156  //
157  // METHOD NAME : Reader::nextNode
158  // METHOD TYPE : bool
159  //
161  {
162  int ret = xmlTextReaderRead( _reader );
163  if ( ret == 1 )
164  {
165  return true;
166  }
167  xmlTextReaderClose( _reader );
168  if ( ret != 0 )
169  {
170  ZYPP_THROW( ParseException() );
171  }
172  return false;
173  }
174 
176  //
177  // METHOD NAME : Reader::nextNodeAttribute
178  // METHOD TYPE : bool
179  //
181  {
182  int ret = xmlTextReaderMoveToNextAttribute( _reader );
183  if ( ret == 1 )
184  {
185  return true;
186  }
187  if ( ret != 0 )
188  {
189  ZYPP_THROW( ParseException() );
190  }
191  return false;
192  }
193 
195  //
196  // METHOD NAME : Reader::close
197  // METHOD TYPE : void
198  //
200  {
201  if ( _reader )
202  {
203  xmlTextReaderClose( _reader );
204  }
205  }
206 
208  //
209  // METHOD NAME : Reader::seekToNode
210  // METHOD TYPE : bool
211  //
212  bool Reader::seekToNode( int depth_r, const std::string & name_r )
213  {
214  do
215  {
216  if ( _node.depth() == depth_r
217  && _node.name() == name_r
218  && _node.nodeType() == XML_READER_TYPE_ELEMENT )
219  {
220  break;
221  }
222  } while( nextNode() );
223 
224  return ! atEnd();
225  }
226 
228  //
229  // METHOD NAME : Reader::seekToEndNode
230  // METHOD TYPE : bool
231  //
232  bool Reader::seekToEndNode( int depth_r, const std::string & name_r )
233  {
234  // Empty element has no separate end node: <node/>
235  do
236  {
237  if ( _node.depth() == depth_r
238  && _node.name() == name_r
239  && ( _node.nodeType() == XML_READER_TYPE_END_ELEMENT
240  || ( _node.nodeType() == XML_READER_TYPE_ELEMENT
241  && _node.isEmptyElement() ) ) )
242  {
243  break;
244  }
245  } while( nextNode() );
246 
247  return ! atEnd();
248  }
249 
251  } // namespace xml
254 } // namespace zypp
std::ostream & node(std::ostream &out_r, const std::string &name_r, Node::Attr attr_r)
Definition: Xml.h:203
#define MIL
Definition: Logger.h:79
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
Reader(const InputStream &stream_r, const Validate &validate_r=Validate::none())
Ctor.
Definition: Reader.cc:106
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:83
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:1041
xmlChar * wrapper.
Definition: XmlString.h:40
Definition: Arch.h:344
Helper to create and pass std::istream.
Definition: InputStream.h:56
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
DBusError error
Definition: HalContext.cc:100
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:127
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
bool nextNode()
Definition: Reader.cc:160
bool seekToNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:212
xmlTextReaderPtr _reader
Definition: Reader.h:192
#define WAR
Definition: Logger.h:80
bool seekToEndNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:232
InputStream _stream
Definition: Reader.h:191
int depth() const
The depth of the node in the tree.
Definition: Node.h:62
#define X(T)
xmlTextReader document validation.
Definition: Reader.h:37
bool atEnd() const
Definition: Reader.h:128
bool nextNodeAttribute()
Definition: Reader.cc:180
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:140
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:131
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