libzypp
10.5.0
|
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