Orocos Real-Time Toolkit  2.9.0
CPFDemarshaller.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Tue Apr 5 16:53:25 CEST 2005 CPFDemarshaller.cxx
3 
4  CPFDemarshaller.cxx - description
5  -------------------
6  begin : Tue April 05 2005
7  copyright : (C) 2005 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 
40 #include "CPFDemarshaller.hpp"
41 #include "CPFDTD.hpp"
42 
43 #ifdef OROPKG_SUPPORT_XERCES_C
44 #include <xercesc/util/PlatformUtils.hpp>
45 #include <xercesc/util/TransService.hpp>
46 #include <xercesc/sax2/SAX2XMLReader.hpp>
47 #include <xercesc/sax2/XMLReaderFactory.hpp>
48 #include <xercesc/sax2/DefaultHandler.hpp>
49 #include <xercesc/sax2/Attributes.hpp>
50 #include <xercesc/util/XMLUniDefs.hpp>
51 #include <xercesc/util/BinMemInputStream.hpp>
52 #include <xercesc/framework/LocalFileInputSource.hpp>
53 #include <xercesc/framework/MemBufInputSource.hpp>
54 #include <xercesc/validators/common/Grammar.hpp>
55 
56 #include <vector>
57 #include <stack>
58 #include <map>
59 #include <string>
60 #include <iostream>
61 #include <cstdio>
62 
63 #include <Property.hpp>
64 #include "../base/PropertyIntrospection.hpp"
65 #include <Logger.hpp>
66 
67 namespace RTT
68 {
69 #ifdef XERCES_CPP_NAMESPACE
70  using namespace XERCES_CPP_NAMESPACE;
71 #endif
72  using namespace marsh;
73  using namespace base;
74 
75  inline bool XMLChToStdString(const XMLCh* const c, std::string& res)
76  {
77  char* chholder;
78  chholder = XMLString::transcode( c );
79  if ( chholder ) {
80  res = chholder;
81  XMLString::release( &chholder );
82  return true;
83  }
84  log(Error) << "Could not transcode XMLCh* !" <<endlog();
85  return false;
86  }
87 
88  inline std::string XMLgetString(const XMLCh* const c)
89  {
90  std::string res;
91  char* chholder;
92  chholder = XMLString::transcode( c );
93  if ( chholder ) {
94  res = chholder;
95  XMLString::release( &chholder );
96  return res;
97  }
98  log(Error) << "Could not transcode XMLCh* !" <<endlog();
99  return res;
100  }
101 
102  class SAX2CPFHandler : public DefaultHandler
103  {
104 
108  PropertyBag &bag;
109  std::stack< std::pair<PropertyBag*, Property<PropertyBag>*> > bag_stack;
110 
111  enum Tag { TAG_STRUCT, TAG_SIMPLE, TAG_SEQUENCE, TAG_PROPERTIES, TAG_DESCRIPTION, TAG_VALUE, TAG_UNKNOWN};
112  std::stack<Tag> tag_stack;
113 
117  std::string name;
118  std::string description;
119  std::string type;
120  std::string value_string;
121 
122  public:
123 
124  SAX2CPFHandler( PropertyBag &b ) : bag( b )
125  {
126  Property<PropertyBag>* dummy = 0;
127  bag_stack.push(std::make_pair(&bag, dummy));
128  }
129 
130  void endElement( const XMLCh* const uri,
131  const XMLCh* const localname,
132  const XMLCh* const qname )
133  {
134  //char *ln = XMLString::transcode( localname );
135 
136 // if ( value_string.empty() ) {
137 // Logger::log()<<Logger::Debug << "SAX2CPFHandler : Empty value for property."
138 // <<Logger::endl;
139 // }
140  switch ( tag_stack.top() )
141  {
142  case TAG_SIMPLE:
143  if ( type == "boolean" )
144  {
145  if ( value_string == "1" || value_string == "true")
146  bag_stack.top().first->ownProperty
147  ( new Property<bool>( name, description, true ) );
148  else if ( value_string == "0" || value_string == "false" )
149  bag_stack.top().first->ownProperty
150  ( new Property<bool>( name, description, false ) );
151  else
152  throw SAXException(std::string("Wrong value for property '"+type+"'." \
153  " Value should contain '0' or '1', got '"+ value_string +"'.").c_str());
154  }
155  else if ( type == "char" ) {
156  if ( value_string.empty() )
157  bag_stack.top().first->ownProperty( new Property<char>( name, description, '\0' ) );
158  else
159  if ( value_string.length() != 1 )
160  throw SAXException(std::string("Wrong value for property '"+type+"'." \
161  " Value should contain a single character, got '"+ value_string +"'.").c_str());
162  else
163  bag_stack.top().first->ownProperty( new Property<char>( name, description, value_string[0] ) );
164  }
165  else if ( type == "uchar" || type == "octet" ) {
166  if ( value_string.length() != 1 )
167  throw SAXException(std::string("Wrong value for property '"+type+"'." \
168  " Value should contain a single unsigned character, got '"+ value_string +"'.").c_str());
169  else
170  bag_stack.top().first->ownProperty
171  ( new Property<unsigned char>( name, description, value_string[0] ) );
172  }
173  else if ( type == "long" || type == "short")
174  {
175  int v;
176  if ( sscanf(value_string.c_str(), "%d", &v) == 1)
177  bag_stack.top().first->ownProperty( new Property<int>( name, description, v ) );
178  else
179  throw SAXException(std::string("Wrong value for property '"+type+"'." \
180  " Value should contain an integer value, got '"+ value_string +"'.").c_str());
181  }
182  else if ( type == "ulong" || type == "ushort")
183  {
184  unsigned int v;
185  if ( sscanf(value_string.c_str(), "%u", &v) == 1)
186  bag_stack.top().first->ownProperty( new Property<unsigned int>( name, description, v ) );
187  else
188  throw SAXException(std::string("Wrong value for property '"+type+"'." \
189  " Value should contain an integer value, got '"+ value_string +"'.").c_str());
190  }
191  else if ( type == "llong")
192  {
193  long long v;
194  if ( sscanf(value_string.c_str(), "%lld", &v) == 1)
195  bag_stack.top().first->ownProperty( new Property<long long>( name, description, v ) );
196  else
197  throw SAXException(std::string("Wrong value for property '"+type+"'." \
198  " Value should contain an integer value, got '"+ value_string +"'.").c_str());
199  }
200  else if ( type == "ullong")
201  {
202  unsigned long long v;
203  if ( sscanf(value_string.c_str(), "%llu", &v) == 1)
204  bag_stack.top().first->ownProperty( new Property<unsigned long long>( name, description, v ) );
205  else
206  throw SAXException(std::string("Wrong value for property '"+type+"'." \
207  " Value should contain an integer value, got '"+ value_string +"'.").c_str());
208  }
209  else if ( type == "double")
210  {
211  double v;
212  if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
213  bag_stack.top().first->ownProperty
214  ( new Property<double>( name, description, v ) );
215  else
216  throw SAXException(std::string("Wrong value for property '"+type+"'." \
217  " Value should contain a double value, got '"+ value_string +"'.").c_str());
218  }
219  else if ( type == "float")
220  {
221  float v;
222  if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
223  bag_stack.top().first->ownProperty
224  ( new Property<float>( name, description, v ) );
225  else
226  throw SAXException(std::string("Wrong value for property '"+type+"'." \
227  " Value should contain a float value, got '"+ value_string +"'.").c_str());
228  }
229  else if ( type == "string")
230  bag_stack.top().first->ownProperty
231  ( new Property<std::string>( name, description, value_string ) );
232  tag_stack.pop();
233  value_string.clear(); // cleanup
234  description.clear();
235  name.clear();
236  break;
237 
238  case TAG_SEQUENCE:
239  case TAG_STRUCT:
240  {
241  Property<PropertyBag>* prop = bag_stack.top().second;
242  bag_stack.pop();
243  bag_stack.top().first->ownProperty( prop );
244  //( new Property<PropertyBag>( pn, description, *pb ) );
245  //delete pb;
246  tag_stack.pop();
247  description.clear();
248  name.clear();
249  type.clear();
250  }
251  break;
252 
253  case TAG_DESCRIPTION:
254  tag_stack.pop();
255  if ( tag_stack.top() == TAG_STRUCT ) {
256  // it is a description of a struct that ended
257  bag_stack.top().second->setDescription(description);
258  description.clear();
259  }
260  break;
261  case TAG_VALUE:
262  case TAG_PROPERTIES:
263  case TAG_UNKNOWN:
264  tag_stack.pop();
265  break;
266 
267  }
268  }
269 
270 
271  void startElement( const XMLCh* const uri,
272  const XMLCh* const localname,
273  const XMLCh* const qname,
274  const Attributes& attributes )
275  {
276  std::string ln;
277  XMLChToStdString( localname, ln );
278 
279  if ( ln == "properties" )
280  tag_stack.push( TAG_PROPERTIES );
281  else
282  if ( ln == "simple" )
283  {
284  name.clear();
285  type.clear();
286  tag_stack.push( TAG_SIMPLE );
287  for (unsigned int ac = 0; ac < attributes.getLength(); ++ac)
288  {
289  std::string an;
290  XMLChToStdString( attributes.getLocalName(ac), an );
291  if ( an == "name")
292  {
293  XMLChToStdString( attributes.getValue(ac), name);
294  }
295  else if ( an == "type")
296  {
297  XMLChToStdString( attributes.getValue(ac), type);
298  }
299  }
300  }
301  else
302  if ( ln == "struct" || ln == "sequence")
303  {
304  name.clear();
305  type.clear();
306 
307  for (unsigned int ac = 0; ac < attributes.getLength(); ++ac)
308  {
309  std::string an;
310  XMLChToStdString( attributes.getLocalName(ac), an );
311  if ( an == "name")
312  {
313  XMLChToStdString( attributes.getValue(ac), name);
314  }
315  else if ( an == "type")
316  {
317  XMLChToStdString( attributes.getValue(ac), type);
318  }
319  }
320 
321  if ( ln == "struct" )
322  tag_stack.push( TAG_STRUCT );
323  else {
324  tag_stack.push( TAG_SEQUENCE );
325  type = "Sequence"; // override
326  }
327 
328  Property<PropertyBag> *prop;
329  prop = new Property<PropertyBag>(name,"",PropertyBag(type));
330 
331  // take reference to bag itself !
332  bag_stack.push(std::make_pair( &(prop->value()), prop));
333  }
334  else
335  if ( ln == "description")
336  tag_stack.push( TAG_DESCRIPTION );
337  else
338  if ( ln == "value" )
339  tag_stack.push( TAG_VALUE );
340  else {
341  log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
342  tag_stack.push( TAG_UNKNOWN );
343  }
344  }
345 
346  void warning( const SAXParseException& exception )
347  {
348  std::string warn;
349  XMLChToStdString( exception.getMessage(), warn);
350  Logger::log() << Logger::Warning << "SAX2CPFHandler Parsing: " << warn <<Logger::nl;
351  if ( exception.getPublicId() )
352  {
353  XMLChToStdString( exception.getPublicId(), warn);
354  Logger::log() << " At entity "<< warn <<Logger::nl;
355  }
356  Logger::log() << " Column "<< exception.getColumnNumber()<< " Line " <<exception.getLineNumber()<<Logger::endl;
357  // to not throw.
358  }
359 
360  void error( const SAXParseException& exception )
361  {
362  throw exception;
363  }
364  void fatalError( const SAXParseException& exception )
365  {
366  throw exception;
367  }
368 #if XERCES_VERSION_MAJOR < 3
369  void characters( const XMLCh* const chars, const unsigned int length )
370 #else
371  void characters( const XMLCh* const chars, const XMLSize_t length )
372 #endif
373  {
374  //char *ln = XMLString::transcode( chars );
375  switch ( tag_stack.top() )
376  {
377  case TAG_DESCRIPTION:
378  XMLChToStdString( chars, description);
379  break;
380 
381  case TAG_VALUE:
382  XMLChToStdString( chars, value_string);
383  break;
384  case TAG_STRUCT:
385  case TAG_SIMPLE:
386  case TAG_SEQUENCE:
387  case TAG_PROPERTIES:
388  case TAG_UNKNOWN:
389  break;
390  }
391  }
392 
393 
394  };
395 
396  CPFDemarshaller::CPFDemarshaller( const std::string& filename )
397  : name(0), fis(0)
398  {
399  Logger::In in("CPFDemarshaller");
400  try
401  {
402  XMLPlatformUtils::Initialize();
403  }
404  catch ( const XMLException & toCatch )
405  {
406  std::string error;
407  XMLChToStdString(toCatch.getMessage(), error);
408  Logger::log() << Logger::Error << "XML Initialization : "
409  << error << Logger::endl;
410  }
411  catch ( ... )
412  {
413  Logger::log() << Logger::Error << "XML Init: General System Exception !" << Logger::endl;
414  }
415 
416  try {
417  name = XMLString::transcode( filename.c_str() );
418  fis = new LocalFileInputSource( name );
419  }
420  catch ( XMLException& xe )
421  {
422  Logger::log() << Logger::Error << "Failed to open file " <<filename << Logger::endl;
423  Logger::log() << Logger::Error << xe.getMessage() << Logger::endl;
424 
425  fis = 0;
426  }
427  catch ( ... )
428  {
429  Logger::log() << Logger::Error << "Opening file: General System Exception !" << Logger::endl;
430  }
431  XMLString::release( &name );
432  }
433 
434  CPFDemarshaller::~CPFDemarshaller()
435  {
436  delete fis;
437  XMLPlatformUtils::Terminate();
438  }
439 
440  bool CPFDemarshaller::deserialize( PropertyBag &v )
441  {
442  if ( fis == 0 )
443  return false;
444 
445  SAX2XMLReader* parser = 0;
446  try {
447  XMLPlatformUtils::Initialize();
448  parser = XMLReaderFactory::createXMLReader();
449  }
450  catch ( ... )
451  {
452  Logger::log() << Logger::Error << "SAX2XMLReader System Exception !" << Logger::endl;
453  XMLPlatformUtils::Terminate();
454  return false;
455  }
456 
457 
458  Logger::In in("CPFDemarshaller");
459 
460  try
461  {
462  SAX2CPFHandler handler( v );
463  parser->setContentHandler( &handler );
464  parser->setErrorHandler( &handler );
465  parser->setFeature( XMLUni::fgSAX2CoreValidation, false );
466  parser->setFeature( XMLUni::fgXercesValidationErrorAsFatal, false );
467  parser->setFeature( XMLUni::fgXercesContinueAfterFatalError, false );
468 #if 0
469  parser->setFeature( XMLUni::fgXercesSchemaFullChecking, false );
470  parser->setFeature( XMLUni::fgXercesDynamic, true );
471  parser->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
472  parser->setFeature( XMLUni::fgSAX2CoreNameSpacePrefixes, true );
473  parser->setFeature( XMLUni::fgXercesSchema, false );
474 #endif
475  // try to avoid loading the DTD mentioned in the xml file,
476  // and load our own grammer.
477  using namespace detail;
478  parser->setFeature( XMLUni::fgXercesLoadExternalDTD, false );
479  //parser->setDoValidation(true);
480  int length = XMLString::stringLen(cpf_dtd);// string length
481  XMLByte* buffer = new XMLByte[length];
482  memcpy( buffer, cpf_dtd, length );
483  MemBufInputSource dtd(buffer, length, "internal_cpf.dtd");
484  parser->loadGrammar( dtd, Grammar::DTDGrammarType );
485  delete[] buffer;
486 
487  parser->parse( *fis );
488  parser->getErrorCount();
489  delete parser;
490  XMLPlatformUtils::Terminate();
491  }
492  catch ( const XMLException & toCatch )
493  {
494  Logger::log() << Logger::Error << "An XML parsing error occurred processing file " <<Logger::nl;
495  if ( toCatch.getSrcFile() ) {
496  Logger::log() << toCatch.getSrcFile() << " parsing line " << toCatch.getSrcLine()<<Logger::nl ;
497  }
498  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
499  delete parser;
500  XMLPlatformUtils::Terminate();
501  return false;
502  }
503  catch ( const SAXParseException & toCatch )
504  {
505  Logger::log() << Logger::Error << "An XML SAX parsing error occurred processing file " <<Logger::nl;
506  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
507  if ( toCatch.getPublicId() )
508  {
509  Logger::log() << " At entity "<< XMLgetString(toCatch.getPublicId()) <<Logger::nl;
510  }
511  Logger::log() << " Column "<< toCatch.getColumnNumber()<< " Line " <<toCatch.getLineNumber()<<Logger::endl;
512  delete parser;
513  XMLPlatformUtils::Terminate();
514  return false;
515  }
516  catch ( const SAXException & toCatch )
517  {
518  Logger::log() << Logger::Error << "An XML SAX exception occurred processing file " <<Logger::nl;
519  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
520  delete parser;
521  XMLPlatformUtils::Terminate();
522  return false;
523  }
524  catch ( ... )
525  {
526  Logger::log() << Logger::Error << "General System Exception !" << Logger::endl;
527  delete parser;
528  XMLPlatformUtils::Terminate();
529  return false;
530  }
531  return true;
532  }
533 }
534 
535 #endif
536 
static std::ostream & nl(std::ostream &__os)
Insert a newline &#39; &#39; in the ostream.
Definition: Logger.cpp:373
static std::ostream & endl(std::ostream &__os)
Definition: Logger.cpp:383
static Logger & log()
As Instance(), but more userfriendly.
Definition: Logger.cpp:117
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
Logger & in(const std::string &modname)
Inform the Logger of the entry of a module.
Definition: Logger.cpp:414
const char * cpf_dtd
Definition: CPFDTD.cpp:45