674ad0a818bd9c39810bcb5cf0c1086a9a7cc8c8
[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       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
97       /////////////////////////////////////////////////////////////////
98     } // namespace
99     ///////////////////////////////////////////////////////////////////
100
101     ///////////////////////////////////////////////////////////////////
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
126     ///////////////////////////////////////////////////////////////////
127     //
128     //  METHOD NAME : Reader::~Reader
129     //  METHOD TYPE : Destructor
130     //
131     Reader::~Reader()
132     {
133       if ( _reader )
134         {
135           xmlFreeTextReader( _reader );
136         }
137       MIL << "Done Parsing " << _stream << endl;
138     }
139
140     XmlString Reader::nodeText()
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
155     ///////////////////////////////////////////////////////////////////
156     //
157     //  METHOD NAME : Reader::nextNode
158     //  METHOD TYPE : bool
159     //
160     bool Reader::nextNode()
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
175     ///////////////////////////////////////////////////////////////////
176     //
177     //  METHOD NAME : Reader::nextNodeAttribute
178     //  METHOD TYPE : bool
179     //
180     bool Reader::nextNodeAttribute()
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
194     ///////////////////////////////////////////////////////////////////
195     //
196     //  METHOD NAME : Reader::close
197     //  METHOD TYPE : void
198     //
199     void Reader::close()
200     {
201       if ( _reader )
202         {
203           xmlTextReaderClose( _reader );
204         }
205     }
206
207     ///////////////////////////////////////////////////////////////////
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
227     ///////////////////////////////////////////////////////////////////
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
250     /////////////////////////////////////////////////////////////////
251   } // namespace xml
252   ///////////////////////////////////////////////////////////////////
253   /////////////////////////////////////////////////////////////////
254 } // namespace zypp
255 ///////////////////////////////////////////////////////////////////