libzypp  10.5.0
Reader.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 extern "C"
00013 {
00014 #include <libxml/xmlreader.h>
00015 #include <libxml/xmlerror.h>
00016 }
00017 
00018 #include <iostream>
00019 
00020 #include "zypp/base/LogControl.h"
00021 #include "zypp/base/LogTools.h"
00022 #include "zypp/base/Exception.h"
00023 #include "zypp/base/String.h"
00024 
00025 #include "zypp/parser/xml/Reader.h"
00026 
00027 using std::endl;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace xml
00034   { 
00035 
00037     namespace
00038     { 
00039 
00040       int ioread( void * context_r, char * buffer_r, int bufferLen_r )
00041       {
00042         if ( context_r && buffer_r )
00043           {
00044             return reinterpret_cast<InputStream *>(context_r)
00045                    ->stream().read( buffer_r, bufferLen_r ).gcount();
00046           }
00047         INT << "XML parser error: null pointer check failed " << context_r << ' ' << (void *)buffer_r << endl;
00048         return -1;
00049       }
00050 
00051       int ioclose( void * /*context_r*/ )
00052       { return 0; }
00053 
00054 
00055       std::list<std::string> structuredErrors;
00056       void structuredErrorFunc( void * userData, xmlErrorPtr error )
00057       {
00058         if ( error )
00059         {
00060           // error->message is NL terminated
00061           std::string err( str::form( "%s[%d] %s", Pathname::basename(error->file).c_str(), error->line,
00062                                       str::stripSuffix( error->message, "\n" ).c_str() ) );
00063           structuredErrors.push_back( err );
00064           WAR << err << endl;
00065         }
00066 #if 0
00067         if ( error )
00068         {
00069 #define X(m) SEC << " " << #m << "\t" << error->m << endl
00070 #define XS(m) SEC << " " << #m << "\t" << (error->m?error->m:"NA") << endl
00071             X(domain);
00072             X(code);
00073             XS(message);
00074             X(level);
00075             XS(file);
00076             X(line);
00077             XS(str1);
00078             XS(str2);
00079             XS(str3);
00080             X(int1);
00081             X(int2);
00082             X(ctxt);
00083             X(node);
00084 #undef X
00085 #undef XS
00086         }
00087 #endif
00088       }
00089 
00090       struct ParseException : public Exception
00091       {
00092         ParseException()
00093         : Exception( "Parse error: " + ( structuredErrors.empty() ? std::string("unknown error"): structuredErrors.back() ) )
00094         {
00095           for_( it, structuredErrors.begin(), --structuredErrors.end() )
00096             addHistory( *it );
00097         }
00098       };
00099 
00101     } // namespace
00103 
00105     //
00106     //  METHOD NAME : Reader::Reader
00107     //  METHOD TYPE : Constructor
00108     //
00109     Reader::Reader( const InputStream & stream_r,
00110                     const Validate & validate_r )
00111     : _stream( stream_r )
00112     , _reader( xmlReaderForIO( ioread, ioclose, &_stream,
00113                                stream_r.path().asString().c_str(), "utf-8", XML_PARSE_PEDANTIC ) )
00114     , _node( _reader )
00115     {
00116       MIL << "Start Parsing " << _stream << endl;
00117       if ( ! _reader || ! stream_r.stream().good() )
00118         ZYPP_THROW( Exception( "Bad input stream" ) );
00119       // set error handler
00120       // TODO: Fix using a global lastStructuredError string is not reentrant.
00121       structuredErrors.clear();
00122       xmlTextReaderSetStructuredErrorHandler( _reader, structuredErrorFunc, NULL );
00123       // TODO: set validation
00124 
00125       // advance to 1st node
00126       nextNode();
00127     }
00128 
00130     //
00131     //  METHOD NAME : Reader::~Reader
00132     //  METHOD TYPE : Destructor
00133     //
00134     Reader::~Reader()
00135     {
00136       if ( _reader )
00137         {
00138           xmlFreeTextReader( _reader );
00139         }
00140       MIL << "Done Parsing " << _stream << endl;
00141     }
00142 
00143     XmlString Reader::nodeText()
00144     {
00145       if ( ! _node.isEmptyElement() )
00146       {
00147         if ( nextNode() )
00148         {
00149           if ( _node.nodeType() == XML_READER_TYPE_TEXT )
00150           {
00151             return _node.value();
00152           }
00153         }
00154       }
00155       return XmlString();
00156     }
00157 
00159     //
00160     //  METHOD NAME : Reader::nextNode
00161     //  METHOD TYPE : bool
00162     //
00163     bool Reader::nextNode()
00164     {
00165       int ret = xmlTextReaderRead( _reader );
00166       if ( ret == 1 )
00167         {
00168           return true;
00169         }
00170       xmlTextReaderClose( _reader );
00171       if ( ret != 0 )
00172         {
00173           ZYPP_THROW( ParseException() );
00174         }
00175       return false;
00176     }
00177 
00179     //
00180     //  METHOD NAME : Reader::nextNodeAttribute
00181     //  METHOD TYPE : bool
00182     //
00183     bool Reader::nextNodeAttribute()
00184     {
00185       int ret = xmlTextReaderMoveToNextAttribute( _reader );
00186       if ( ret == 1 )
00187         {
00188           return true;
00189         }
00190       if ( ret != 0 )
00191         {
00192           ZYPP_THROW( ParseException() );
00193         }
00194       return false;
00195     }
00196 
00198     //
00199     //  METHOD NAME : Reader::close
00200     //  METHOD TYPE : void
00201     //
00202     void Reader::close()
00203     {
00204       if ( _reader )
00205         {
00206           xmlTextReaderClose( _reader );
00207         }
00208     }
00209 
00211     //
00212     //  METHOD NAME : Reader::seekToNode
00213     //  METHOD TYPE : bool
00214     //
00215     bool Reader::seekToNode( int depth_r, const std::string & name_r )
00216     {
00217       do
00218         {
00219           if ( _node.depth() == depth_r
00220                && _node.name() == name_r
00221                && _node.nodeType() == XML_READER_TYPE_ELEMENT )
00222             {
00223               break;
00224             }
00225         } while( nextNode() );
00226 
00227       return ! atEnd();
00228     }
00229 
00231     //
00232     //  METHOD NAME : Reader::seekToEndNode
00233     //  METHOD TYPE : bool
00234     //
00235     bool Reader::seekToEndNode( int depth_r, const std::string & name_r )
00236     {
00237       // Empty element has no separate end node: <node/>
00238       do
00239         {
00240           if ( _node.depth() == depth_r
00241                && _node.name() == name_r
00242                && ( _node.nodeType() == XML_READER_TYPE_END_ELEMENT
00243                     || ( _node.nodeType() == XML_READER_TYPE_ELEMENT
00244                          && _node.isEmptyElement() ) ) )
00245             {
00246               break;
00247             }
00248         } while( nextNode() );
00249 
00250       return ! atEnd();
00251     }
00252 
00254   } // namespace xml
00257 } // namespace zypp