Bump to 17.31.23
[platform/upstream/libzypp.git] / zypp / parser / xml / Reader.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/parser/xml/Reader.cc
10  *
11 */
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
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 { /////////////////////////////////////////////////////////////////
29   ///////////////////////////////////////////////////////////////////
30   namespace xml
31   { /////////////////////////////////////////////////////////////////
32
33     ///////////////////////////////////////////////////////////////////
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 #if 0
68         if ( error )
69         {
70 #define X(m) SEC << " " << #m << "\t" << error->m << endl
71 #define XS(m) SEC << " " << #m << "\t" << (error->m?error->m:"NA") << endl
72             X(domain);
73             X(code);
74             XS(message);
75             X(level);
76             XS(file);
77             X(line);
78             XS(str1);
79             XS(str2);
80             XS(str3);
81             X(int1);
82             X(int2);
83             X(ctxt);
84             X(node);
85 #undef X
86 #undef XS
87         }
88 #endif
89       }
90
91       struct ParseException : public Exception
92       {
93         ParseException()
94         : Exception( "Parse error: " + ( structuredErrors.empty() ? std::string("unknown error"): structuredErrors.back() ) )
95         {
96           for_( it, structuredErrors.begin(), --structuredErrors.end() )
97             addHistory( *it );
98         }
99       };
100
101       /////////////////////////////////////////////////////////////////
102     } // namespace
103     ///////////////////////////////////////////////////////////////////
104
105     ///////////////////////////////////////////////////////////////////
106     //
107     //  METHOD NAME : Reader::Reader
108     //  METHOD TYPE : Constructor
109     //
110     Reader::Reader( const InputStream & stream_r,
111                     const Validate & validate_r )
112     : _stream( stream_r )
113     , _reader( xmlReaderForIO( ioread, ioclose, &_stream,
114                                stream_r.path().asString().c_str(), "utf-8", XML_PARSE_PEDANTIC ) )
115     , _node( _reader )
116     {
117       MIL << "Start Parsing " << _stream << endl;
118       if ( ! _reader || ! stream_r.stream().good() )
119         ZYPP_THROW( Exception( "Bad input stream" ) );
120       // set error handler
121       // TODO: Fix using a global lastStructuredError string is not reentrant.
122       structuredErrors.clear();
123       xmlTextReaderSetStructuredErrorHandler( _reader, structuredErrorFunc, NULL );
124       // TODO: set validation
125
126       // advance to 1st node
127       nextNode();
128     }
129
130     ///////////////////////////////////////////////////////////////////
131     //
132     //  METHOD NAME : Reader::~Reader
133     //  METHOD TYPE : Destructor
134     //
135     Reader::~Reader()
136     {
137       if ( _reader )
138         {
139           xmlFreeTextReader( _reader );
140         }
141       MIL << "Done Parsing " << _stream << endl;
142     }
143
144     XmlString Reader::nodeText()
145     {
146       if ( ! _node.isEmptyElement() )
147       {
148         if ( nextNode() )
149         {
150           if ( _node.nodeType() == XML_READER_TYPE_TEXT )
151           {
152             return _node.value();
153           }
154         }
155       }
156       return XmlString();
157     }
158
159     ///////////////////////////////////////////////////////////////////
160     //
161     //  METHOD NAME : Reader::nextNode
162     //  METHOD TYPE : bool
163     //
164     bool Reader::nextNode()
165     {
166       int ret = xmlTextReaderRead( _reader );
167       if ( ret == 1 )
168         {
169           return true;
170         }
171       xmlTextReaderClose( _reader );
172       if ( ret != 0 )
173         {
174           ZYPP_THROW( ParseException() );
175         }
176       return false;
177     }
178
179     ///////////////////////////////////////////////////////////////////
180     //
181     //  METHOD NAME : Reader::nextNodeAttribute
182     //  METHOD TYPE : bool
183     //
184     bool Reader::nextNodeAttribute()
185     {
186       int ret = xmlTextReaderMoveToNextAttribute( _reader );
187       if ( ret == 1 )
188         {
189           return true;
190         }
191       if ( ret != 0 )
192         {
193           ZYPP_THROW( ParseException() );
194         }
195       return false;
196     }
197
198     ///////////////////////////////////////////////////////////////////
199     //
200     //  METHOD NAME : Reader::close
201     //  METHOD TYPE : void
202     //
203     void Reader::close()
204     {
205       if ( _reader )
206         {
207           xmlTextReaderClose( _reader );
208         }
209     }
210
211     ///////////////////////////////////////////////////////////////////
212     //
213     //  METHOD NAME : Reader::seekToNode
214     //  METHOD TYPE : bool
215     //
216     bool Reader::seekToNode( int depth_r, const std::string & name_r )
217     {
218       do
219         {
220           if ( _node.depth() == depth_r
221                && _node.name() == name_r
222                && _node.nodeType() == XML_READER_TYPE_ELEMENT )
223             {
224               break;
225             }
226         } while( nextNode() );
227
228       return ! atEnd();
229     }
230
231     ///////////////////////////////////////////////////////////////////
232     //
233     //  METHOD NAME : Reader::seekToEndNode
234     //  METHOD TYPE : bool
235     //
236     bool Reader::seekToEndNode( int depth_r, const std::string & name_r )
237     {
238       // Empty element has no separate end node: <node/>
239       do
240         {
241           if ( _node.depth() == depth_r
242                && _node.name() == name_r
243                && ( _node.nodeType() == XML_READER_TYPE_END_ELEMENT
244                     || ( _node.nodeType() == XML_READER_TYPE_ELEMENT
245                          && _node.isEmptyElement() ) ) )
246             {
247               break;
248             }
249         } while( nextNode() );
250
251       return ! atEnd();
252     }
253
254     /////////////////////////////////////////////////////////////////
255   } // namespace xml
256   ///////////////////////////////////////////////////////////////////
257   /////////////////////////////////////////////////////////////////
258 } // namespace zypp
259 ///////////////////////////////////////////////////////////////////