Orocos Real-Time Toolkit
2.5.0
|
00001 /*************************************************************************** 00002 tag: Peter Soetens Tue Apr 5 16:53:25 CEST 2005 CPFDemarshaller.cxx 00003 00004 CPFDemarshaller.cxx - description 00005 ------------------- 00006 begin : Tue April 05 2005 00007 copyright : (C) 2005 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.ac.be 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 00040 #include "CPFDemarshaller.hpp" 00041 #include "CPFDTD.hpp" 00042 00043 #ifdef OROPKG_SUPPORT_XERCES_C 00044 #include <xercesc/util/PlatformUtils.hpp> 00045 #include <xercesc/util/TransService.hpp> 00046 #include <xercesc/sax2/SAX2XMLReader.hpp> 00047 #include <xercesc/sax2/XMLReaderFactory.hpp> 00048 #include <xercesc/sax2/DefaultHandler.hpp> 00049 #include <xercesc/sax2/Attributes.hpp> 00050 #include <xercesc/util/XMLUniDefs.hpp> 00051 #include <xercesc/util/BinMemInputStream.hpp> 00052 #include <xercesc/framework/LocalFileInputSource.hpp> 00053 #include <xercesc/framework/MemBufInputSource.hpp> 00054 #include <xercesc/validators/common/Grammar.hpp> 00055 00056 #include <vector> 00057 #include <stack> 00058 #include <map> 00059 #include <string> 00060 #include <iostream> 00061 #include <cstdio> 00062 00063 #include <Property.hpp> 00064 #include "../base/PropertyIntrospection.hpp" 00065 #include <Logger.hpp> 00066 00067 namespace RTT 00068 { 00069 #ifdef XERCES_CPP_NAMESPACE 00070 using namespace XERCES_CPP_NAMESPACE; 00071 #endif 00072 using namespace marsh; 00073 using namespace base; 00074 00075 inline bool XMLChToStdString(const XMLCh* const c, std::string& res) 00076 { 00077 char* chholder; 00078 chholder = XMLString::transcode( c ); 00079 if ( chholder ) { 00080 res = chholder; 00081 XMLString::release( &chholder ); 00082 return true; 00083 } 00084 log(Error) << "Could not transcode XMLCh* !" <<endlog(); 00085 return false; 00086 } 00087 00088 inline std::string XMLgetString(const XMLCh* const c) 00089 { 00090 std::string res; 00091 char* chholder; 00092 chholder = XMLString::transcode( c ); 00093 if ( chholder ) { 00094 res = chholder; 00095 XMLString::release( &chholder ); 00096 return res; 00097 } 00098 log(Error) << "Could not transcode XMLCh* !" <<endlog(); 00099 return res; 00100 } 00101 00102 class SAX2CPFHandler : public DefaultHandler 00103 { 00104 00108 PropertyBag &bag; 00109 std::stack< std::pair<PropertyBag*, Property<PropertyBag>*> > bag_stack; 00110 00111 enum Tag { TAG_STRUCT, TAG_SIMPLE, TAG_SEQUENCE, TAG_PROPERTIES, TAG_DESCRIPTION, TAG_VALUE, TAG_UNKNOWN}; 00112 std::stack<Tag> tag_stack; 00113 00117 std::string name; 00118 std::string description; 00119 std::string type; 00120 std::string value_string; 00121 00122 public: 00123 00124 SAX2CPFHandler( PropertyBag &b ) : bag( b ) 00125 { 00126 Property<PropertyBag>* dummy = 0; 00127 bag_stack.push(std::make_pair(&bag, dummy)); 00128 } 00129 00130 void endElement( const XMLCh* const uri, 00131 const XMLCh* const localname, 00132 const XMLCh* const qname ) 00133 { 00134 //char *ln = XMLString::transcode( localname ); 00135 00136 // if ( value_string.empty() ) { 00137 // Logger::log()<<Logger::Debug << "SAX2CPFHandler : Empty value for property." 00138 // <<Logger::endl; 00139 // } 00140 switch ( tag_stack.top() ) 00141 { 00142 case TAG_SIMPLE: 00143 if ( type == "boolean" ) 00144 { 00145 if ( value_string == "1" || value_string == "true") 00146 bag_stack.top().first->add 00147 ( new Property<bool>( name, description, true ) ); 00148 else if ( value_string == "0" || value_string == "false" ) 00149 bag_stack.top().first->add 00150 ( new Property<bool>( name, description, false ) ); 00151 else 00152 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00153 " Value should contain '0' or '1', got '"+ value_string +"'.").c_str()); 00154 } 00155 else if ( type == "char" ) { 00156 if ( value_string.empty() ) 00157 bag_stack.top().first->add( new Property<char>( name, description, '\0' ) ); 00158 else 00159 if ( value_string.length() != 1 ) 00160 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00161 " Value should contain a single character, got '"+ value_string +"'.").c_str()); 00162 else 00163 bag_stack.top().first->add( new Property<char>( name, description, value_string[0] ) ); 00164 } 00165 else if ( type == "uchar" || type == "octet" ) { 00166 if ( value_string.length() != 1 ) 00167 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00168 " Value should contain a single unsigned character, got '"+ value_string +"'.").c_str()); 00169 else 00170 bag_stack.top().first->add 00171 ( new Property<unsigned char>( name, description, value_string[0] ) ); 00172 } 00173 else if ( type == "long" || type == "short") 00174 { 00175 int v; 00176 if ( sscanf(value_string.c_str(), "%d", &v) == 1) 00177 bag_stack.top().first->add( new Property<int>( name, description, v ) ); 00178 else 00179 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00180 " Value should contain an integer value, got '"+ value_string +"'.").c_str()); 00181 } 00182 else if ( type == "ulong" || type == "ushort") 00183 { 00184 unsigned int v; 00185 if ( sscanf(value_string.c_str(), "%u", &v) == 1) 00186 bag_stack.top().first->add( new Property<unsigned int>( name, description, v ) ); 00187 else 00188 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00189 " Value should contain an integer value, got '"+ value_string +"'.").c_str()); 00190 } 00191 else if ( type == "double") 00192 { 00193 double v; 00194 if ( sscanf(value_string.c_str(), "%lf", &v) == 1 ) 00195 bag_stack.top().first->add 00196 ( new Property<double>( name, description, v ) ); 00197 else 00198 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00199 " Value should contain a double value, got '"+ value_string +"'.").c_str()); 00200 } 00201 else if ( type == "float") 00202 { 00203 float v; 00204 if ( sscanf(value_string.c_str(), "%f", &v) == 1 ) 00205 bag_stack.top().first->add 00206 ( new Property<float>( name, description, v ) ); 00207 else 00208 throw SAXException(std::string("Wrong value for property '"+type+"'." \ 00209 " Value should contain a float value, got '"+ value_string +"'.").c_str()); 00210 } 00211 else if ( type == "string") 00212 bag_stack.top().first->add 00213 ( new Property<std::string>( name, description, value_string ) ); 00214 tag_stack.pop(); 00215 value_string.clear(); // cleanup 00216 description.clear(); 00217 name.clear(); 00218 break; 00219 00220 case TAG_SEQUENCE: 00221 case TAG_STRUCT: 00222 { 00223 Property<PropertyBag>* prop = bag_stack.top().second; 00224 bag_stack.pop(); 00225 bag_stack.top().first->add( prop ); 00226 //( new Property<PropertyBag>( pn, description, *pb ) ); 00227 //delete pb; 00228 tag_stack.pop(); 00229 description.clear(); 00230 name.clear(); 00231 type.clear(); 00232 } 00233 break; 00234 00235 case TAG_DESCRIPTION: 00236 tag_stack.pop(); 00237 if ( tag_stack.top() == TAG_STRUCT ) { 00238 // it is a description of a struct that ended 00239 bag_stack.top().second->setDescription(description); 00240 description.clear(); 00241 } 00242 break; 00243 case TAG_VALUE: 00244 case TAG_PROPERTIES: 00245 case TAG_UNKNOWN: 00246 tag_stack.pop(); 00247 break; 00248 00249 } 00250 } 00251 00252 00253 void startElement( const XMLCh* const uri, 00254 const XMLCh* const localname, 00255 const XMLCh* const qname, 00256 const Attributes& attributes ) 00257 { 00258 std::string ln; 00259 XMLChToStdString( localname, ln ); 00260 00261 if ( ln == "properties" ) 00262 tag_stack.push( TAG_PROPERTIES ); 00263 else 00264 if ( ln == "simple" ) 00265 { 00266 name.clear(); 00267 type.clear(); 00268 tag_stack.push( TAG_SIMPLE ); 00269 for (unsigned int ac = 0; ac < attributes.getLength(); ++ac) 00270 { 00271 std::string an; 00272 XMLChToStdString( attributes.getLocalName(ac), an ); 00273 if ( an == "name") 00274 { 00275 XMLChToStdString( attributes.getValue(ac), name); 00276 } 00277 else if ( an == "type") 00278 { 00279 XMLChToStdString( attributes.getValue(ac), type); 00280 } 00281 } 00282 } 00283 else 00284 if ( ln == "struct" || ln == "sequence") 00285 { 00286 name.clear(); 00287 type.clear(); 00288 00289 for (unsigned int ac = 0; ac < attributes.getLength(); ++ac) 00290 { 00291 std::string an; 00292 XMLChToStdString( attributes.getLocalName(ac), an ); 00293 if ( an == "name") 00294 { 00295 XMLChToStdString( attributes.getValue(ac), name); 00296 } 00297 else if ( an == "type") 00298 { 00299 XMLChToStdString( attributes.getValue(ac), type); 00300 } 00301 } 00302 00303 if ( ln == "struct" ) 00304 tag_stack.push( TAG_STRUCT ); 00305 else { 00306 tag_stack.push( TAG_SEQUENCE ); 00307 type = "Sequence"; // override 00308 } 00309 00310 Property<PropertyBag> *prop; 00311 prop = new Property<PropertyBag>(name,"",PropertyBag(type)); 00312 00313 // take reference to bag itself ! 00314 bag_stack.push(std::make_pair( &(prop->value()), prop)); 00315 } 00316 else 00317 if ( ln == "description") 00318 tag_stack.push( TAG_DESCRIPTION ); 00319 else 00320 if ( ln == "value" ) 00321 tag_stack.push( TAG_VALUE ); 00322 else { 00323 log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog(); 00324 tag_stack.push( TAG_UNKNOWN ); 00325 } 00326 } 00327 00328 void warning( const SAXParseException& exception ) 00329 { 00330 std::string warn; 00331 XMLChToStdString( exception.getMessage(), warn); 00332 Logger::log() << Logger::Warning << "SAX2CPFHandler Parsing: " << warn <<Logger::nl; 00333 if ( exception.getPublicId() ) 00334 { 00335 XMLChToStdString( exception.getPublicId(), warn); 00336 Logger::log() << " At entity "<< warn <<Logger::nl; 00337 } 00338 Logger::log() << " Column "<< exception.getColumnNumber()<< " Line " <<exception.getLineNumber()<<Logger::endl; 00339 // to not throw. 00340 } 00341 00342 void error( const SAXParseException& exception ) 00343 { 00344 throw exception; 00345 } 00346 void fatalError( const SAXParseException& exception ) 00347 { 00348 throw exception; 00349 } 00350 #if XERCES_VERSION_MAJOR < 3 00351 void characters( const XMLCh* const chars, const unsigned int length ) 00352 #else 00353 void characters( const XMLCh* const chars, const XMLSize_t length ) 00354 #endif 00355 { 00356 //char *ln = XMLString::transcode( chars ); 00357 switch ( tag_stack.top() ) 00358 { 00359 case TAG_DESCRIPTION: 00360 XMLChToStdString( chars, description); 00361 break; 00362 00363 case TAG_VALUE: 00364 XMLChToStdString( chars, value_string); 00365 break; 00366 case TAG_STRUCT: 00367 case TAG_SIMPLE: 00368 case TAG_SEQUENCE: 00369 case TAG_PROPERTIES: 00370 case TAG_UNKNOWN: 00371 break; 00372 } 00373 } 00374 00375 00376 }; 00377 00378 CPFDemarshaller::CPFDemarshaller( const std::string& filename ) 00379 : name(0), fis(0) 00380 { 00381 Logger::In in("CPFDemarshaller"); 00382 try 00383 { 00384 XMLPlatformUtils::Initialize(); 00385 } 00386 catch ( const XMLException & toCatch ) 00387 { 00388 std::string error; 00389 XMLChToStdString(toCatch.getMessage(), error); 00390 Logger::log() << Logger::Error << "XML Initialization : " 00391 << error << Logger::endl; 00392 } 00393 catch ( ... ) 00394 { 00395 Logger::log() << Logger::Error << "XML Init: General System Exception !" << Logger::endl; 00396 } 00397 00398 try { 00399 name = XMLString::transcode( filename.c_str() ); 00400 fis = new LocalFileInputSource( name ); 00401 } 00402 catch ( XMLException& xe ) 00403 { 00404 Logger::log() << Logger::Error << "Failed to open file " <<filename << Logger::endl; 00405 Logger::log() << Logger::Error << xe.getMessage() << Logger::endl; 00406 00407 fis = 0; 00408 } 00409 catch ( ... ) 00410 { 00411 Logger::log() << Logger::Error << "Opening file: General System Exception !" << Logger::endl; 00412 } 00413 XMLString::release( &name ); 00414 } 00415 00416 CPFDemarshaller::~CPFDemarshaller() 00417 { 00418 delete fis; 00419 XMLPlatformUtils::Terminate(); 00420 } 00421 00422 bool CPFDemarshaller::deserialize( PropertyBag &v ) 00423 { 00424 if ( fis == 0 ) 00425 return false; 00426 00427 SAX2XMLReader* parser = 0; 00428 try { 00429 XMLPlatformUtils::Initialize(); 00430 parser = XMLReaderFactory::createXMLReader(); 00431 } 00432 catch ( ... ) 00433 { 00434 Logger::log() << Logger::Error << "SAX2XMLReader System Exception !" << Logger::endl; 00435 XMLPlatformUtils::Terminate(); 00436 return false; 00437 } 00438 00439 00440 Logger::In in("CPFDemarshaller"); 00441 00442 try 00443 { 00444 SAX2CPFHandler handler( v ); 00445 parser->setContentHandler( &handler ); 00446 parser->setErrorHandler( &handler ); 00447 parser->setFeature( XMLUni::fgSAX2CoreValidation, false ); 00448 parser->setFeature( XMLUni::fgXercesValidationErrorAsFatal, false ); 00449 parser->setFeature( XMLUni::fgXercesContinueAfterFatalError, false ); 00450 #if 0 00451 parser->setFeature( XMLUni::fgXercesSchemaFullChecking, false ); 00452 parser->setFeature( XMLUni::fgXercesDynamic, true ); 00453 parser->setFeature( XMLUni::fgSAX2CoreNameSpaces, true ); 00454 parser->setFeature( XMLUni::fgSAX2CoreNameSpacePrefixes, true ); 00455 parser->setFeature( XMLUni::fgXercesSchema, false ); 00456 #endif 00457 // try to avoid loading the DTD mentioned in the xml file, 00458 // and load our own grammer. 00459 using namespace detail; 00460 parser->setFeature( XMLUni::fgXercesLoadExternalDTD, false ); 00461 //parser->setDoValidation(true); 00462 int length = XMLString::stringLen(cpf_dtd);// string length 00463 XMLByte* buffer = new XMLByte[length]; 00464 memcpy( buffer, cpf_dtd, length ); 00465 MemBufInputSource dtd(buffer, length, "internal_cpf.dtd"); 00466 parser->loadGrammar( dtd, Grammar::DTDGrammarType ); 00467 delete[] buffer; 00468 00469 parser->parse( *fis ); 00470 parser->getErrorCount(); 00471 delete parser; 00472 XMLPlatformUtils::Terminate(); 00473 } 00474 catch ( const XMLException & toCatch ) 00475 { 00476 Logger::log() << Logger::Error << "An XML parsing error occurred processing file " <<Logger::nl; 00477 if ( toCatch.getSrcFile() ) { 00478 Logger::log() << toCatch.getSrcFile() << " parsing line " << toCatch.getSrcLine()<<Logger::nl ; 00479 } 00480 Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl; 00481 delete parser; 00482 XMLPlatformUtils::Terminate(); 00483 return false; 00484 } 00485 catch ( const SAXParseException & toCatch ) 00486 { 00487 Logger::log() << Logger::Error << "An XML SAX parsing error occurred processing file " <<Logger::nl; 00488 Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl; 00489 if ( toCatch.getPublicId() ) 00490 { 00491 Logger::log() << " At entity "<< XMLgetString(toCatch.getPublicId()) <<Logger::nl; 00492 } 00493 Logger::log() << " Column "<< toCatch.getColumnNumber()<< " Line " <<toCatch.getLineNumber()<<Logger::endl; 00494 delete parser; 00495 XMLPlatformUtils::Terminate(); 00496 return false; 00497 } 00498 catch ( const SAXException & toCatch ) 00499 { 00500 Logger::log() << Logger::Error << "An XML SAX exception occurred processing file " <<Logger::nl; 00501 Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl; 00502 delete parser; 00503 XMLPlatformUtils::Terminate(); 00504 return false; 00505 } 00506 catch ( ... ) 00507 { 00508 Logger::log() << Logger::Error << "General System Exception !" << Logger::endl; 00509 delete parser; 00510 XMLPlatformUtils::Terminate(); 00511 return false; 00512 } 00513 return true; 00514 } 00515 } 00516 00517 #endif 00518