Orocos Real-Time Toolkit  2.8.3
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 == "double")
192  {
193  double v;
194  if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
195  bag_stack.top().first->ownProperty
196  ( new Property<double>( name, description, v ) );
197  else
198  throw SAXException(std::string("Wrong value for property '"+type+"'." \
199  " Value should contain a double value, got '"+ value_string +"'.").c_str());
200  }
201  else if ( type == "float")
202  {
203  float v;
204  if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
205  bag_stack.top().first->ownProperty
206  ( new Property<float>( name, description, v ) );
207  else
208  throw SAXException(std::string("Wrong value for property '"+type+"'." \
209  " Value should contain a float value, got '"+ value_string +"'.").c_str());
210  }
211  else if ( type == "string")
212  bag_stack.top().first->ownProperty
213  ( new Property<std::string>( name, description, value_string ) );
214  tag_stack.pop();
215  value_string.clear(); // cleanup
216  description.clear();
217  name.clear();
218  break;
219 
220  case TAG_SEQUENCE:
221  case TAG_STRUCT:
222  {
223  Property<PropertyBag>* prop = bag_stack.top().second;
224  bag_stack.pop();
225  bag_stack.top().first->ownProperty( prop );
226  //( new Property<PropertyBag>( pn, description, *pb ) );
227  //delete pb;
228  tag_stack.pop();
229  description.clear();
230  name.clear();
231  type.clear();
232  }
233  break;
234 
235  case TAG_DESCRIPTION:
236  tag_stack.pop();
237  if ( tag_stack.top() == TAG_STRUCT ) {
238  // it is a description of a struct that ended
239  bag_stack.top().second->setDescription(description);
240  description.clear();
241  }
242  break;
243  case TAG_VALUE:
244  case TAG_PROPERTIES:
245  case TAG_UNKNOWN:
246  tag_stack.pop();
247  break;
248 
249  }
250  }
251 
252 
253  void startElement( const XMLCh* const uri,
254  const XMLCh* const localname,
255  const XMLCh* const qname,
256  const Attributes& attributes )
257  {
258  std::string ln;
259  XMLChToStdString( localname, ln );
260 
261  if ( ln == "properties" )
262  tag_stack.push( TAG_PROPERTIES );
263  else
264  if ( ln == "simple" )
265  {
266  name.clear();
267  type.clear();
268  tag_stack.push( TAG_SIMPLE );
269  for (unsigned int ac = 0; ac < attributes.getLength(); ++ac)
270  {
271  std::string an;
272  XMLChToStdString( attributes.getLocalName(ac), an );
273  if ( an == "name")
274  {
275  XMLChToStdString( attributes.getValue(ac), name);
276  }
277  else if ( an == "type")
278  {
279  XMLChToStdString( attributes.getValue(ac), type);
280  }
281  }
282  }
283  else
284  if ( ln == "struct" || ln == "sequence")
285  {
286  name.clear();
287  type.clear();
288 
289  for (unsigned int ac = 0; ac < attributes.getLength(); ++ac)
290  {
291  std::string an;
292  XMLChToStdString( attributes.getLocalName(ac), an );
293  if ( an == "name")
294  {
295  XMLChToStdString( attributes.getValue(ac), name);
296  }
297  else if ( an == "type")
298  {
299  XMLChToStdString( attributes.getValue(ac), type);
300  }
301  }
302 
303  if ( ln == "struct" )
304  tag_stack.push( TAG_STRUCT );
305  else {
306  tag_stack.push( TAG_SEQUENCE );
307  type = "Sequence"; // override
308  }
309 
310  Property<PropertyBag> *prop;
311  prop = new Property<PropertyBag>(name,"",PropertyBag(type));
312 
313  // take reference to bag itself !
314  bag_stack.push(std::make_pair( &(prop->value()), prop));
315  }
316  else
317  if ( ln == "description")
318  tag_stack.push( TAG_DESCRIPTION );
319  else
320  if ( ln == "value" )
321  tag_stack.push( TAG_VALUE );
322  else {
323  log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
324  tag_stack.push( TAG_UNKNOWN );
325  }
326  }
327 
328  void warning( const SAXParseException& exception )
329  {
330  std::string warn;
331  XMLChToStdString( exception.getMessage(), warn);
332  Logger::log() << Logger::Warning << "SAX2CPFHandler Parsing: " << warn <<Logger::nl;
333  if ( exception.getPublicId() )
334  {
335  XMLChToStdString( exception.getPublicId(), warn);
336  Logger::log() << " At entity "<< warn <<Logger::nl;
337  }
338  Logger::log() << " Column "<< exception.getColumnNumber()<< " Line " <<exception.getLineNumber()<<Logger::endl;
339  // to not throw.
340  }
341 
342  void error( const SAXParseException& exception )
343  {
344  throw exception;
345  }
346  void fatalError( const SAXParseException& exception )
347  {
348  throw exception;
349  }
350 #if XERCES_VERSION_MAJOR < 3
351  void characters( const XMLCh* const chars, const unsigned int length )
352 #else
353  void characters( const XMLCh* const chars, const XMLSize_t length )
354 #endif
355  {
356  //char *ln = XMLString::transcode( chars );
357  switch ( tag_stack.top() )
358  {
359  case TAG_DESCRIPTION:
360  XMLChToStdString( chars, description);
361  break;
362 
363  case TAG_VALUE:
364  XMLChToStdString( chars, value_string);
365  break;
366  case TAG_STRUCT:
367  case TAG_SIMPLE:
368  case TAG_SEQUENCE:
369  case TAG_PROPERTIES:
370  case TAG_UNKNOWN:
371  break;
372  }
373  }
374 
375 
376  };
377 
378  CPFDemarshaller::CPFDemarshaller( const std::string& filename )
379  : name(0), fis(0)
380  {
381  Logger::In in("CPFDemarshaller");
382  try
383  {
384  XMLPlatformUtils::Initialize();
385  }
386  catch ( const XMLException & toCatch )
387  {
388  std::string error;
389  XMLChToStdString(toCatch.getMessage(), error);
390  Logger::log() << Logger::Error << "XML Initialization : "
391  << error << Logger::endl;
392  }
393  catch ( ... )
394  {
395  Logger::log() << Logger::Error << "XML Init: General System Exception !" << Logger::endl;
396  }
397 
398  try {
399  name = XMLString::transcode( filename.c_str() );
400  fis = new LocalFileInputSource( name );
401  }
402  catch ( XMLException& xe )
403  {
404  Logger::log() << Logger::Error << "Failed to open file " <<filename << Logger::endl;
405  Logger::log() << Logger::Error << xe.getMessage() << Logger::endl;
406 
407  fis = 0;
408  }
409  catch ( ... )
410  {
411  Logger::log() << Logger::Error << "Opening file: General System Exception !" << Logger::endl;
412  }
413  XMLString::release( &name );
414  }
415 
416  CPFDemarshaller::~CPFDemarshaller()
417  {
418  delete fis;
419  XMLPlatformUtils::Terminate();
420  }
421 
422  bool CPFDemarshaller::deserialize( PropertyBag &v )
423  {
424  if ( fis == 0 )
425  return false;
426 
427  SAX2XMLReader* parser = 0;
428  try {
429  XMLPlatformUtils::Initialize();
430  parser = XMLReaderFactory::createXMLReader();
431  }
432  catch ( ... )
433  {
434  Logger::log() << Logger::Error << "SAX2XMLReader System Exception !" << Logger::endl;
435  XMLPlatformUtils::Terminate();
436  return false;
437  }
438 
439 
440  Logger::In in("CPFDemarshaller");
441 
442  try
443  {
444  SAX2CPFHandler handler( v );
445  parser->setContentHandler( &handler );
446  parser->setErrorHandler( &handler );
447  parser->setFeature( XMLUni::fgSAX2CoreValidation, false );
448  parser->setFeature( XMLUni::fgXercesValidationErrorAsFatal, false );
449  parser->setFeature( XMLUni::fgXercesContinueAfterFatalError, false );
450 #if 0
451  parser->setFeature( XMLUni::fgXercesSchemaFullChecking, false );
452  parser->setFeature( XMLUni::fgXercesDynamic, true );
453  parser->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
454  parser->setFeature( XMLUni::fgSAX2CoreNameSpacePrefixes, true );
455  parser->setFeature( XMLUni::fgXercesSchema, false );
456 #endif
457  // try to avoid loading the DTD mentioned in the xml file,
458  // and load our own grammer.
459  using namespace detail;
460  parser->setFeature( XMLUni::fgXercesLoadExternalDTD, false );
461  //parser->setDoValidation(true);
462  int length = XMLString::stringLen(cpf_dtd);// string length
463  XMLByte* buffer = new XMLByte[length];
464  memcpy( buffer, cpf_dtd, length );
465  MemBufInputSource dtd(buffer, length, "internal_cpf.dtd");
466  parser->loadGrammar( dtd, Grammar::DTDGrammarType );
467  delete[] buffer;
468 
469  parser->parse( *fis );
470  parser->getErrorCount();
471  delete parser;
472  XMLPlatformUtils::Terminate();
473  }
474  catch ( const XMLException & toCatch )
475  {
476  Logger::log() << Logger::Error << "An XML parsing error occurred processing file " <<Logger::nl;
477  if ( toCatch.getSrcFile() ) {
478  Logger::log() << toCatch.getSrcFile() << " parsing line " << toCatch.getSrcLine()<<Logger::nl ;
479  }
480  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
481  delete parser;
482  XMLPlatformUtils::Terminate();
483  return false;
484  }
485  catch ( const SAXParseException & toCatch )
486  {
487  Logger::log() << Logger::Error << "An XML SAX parsing error occurred processing file " <<Logger::nl;
488  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
489  if ( toCatch.getPublicId() )
490  {
491  Logger::log() << " At entity "<< XMLgetString(toCatch.getPublicId()) <<Logger::nl;
492  }
493  Logger::log() << " Column "<< toCatch.getColumnNumber()<< " Line " <<toCatch.getLineNumber()<<Logger::endl;
494  delete parser;
495  XMLPlatformUtils::Terminate();
496  return false;
497  }
498  catch ( const SAXException & toCatch )
499  {
500  Logger::log() << Logger::Error << "An XML SAX exception occurred processing file " <<Logger::nl;
501  Logger::log() << XMLgetString(toCatch.getMessage()) <<Logger::endl;
502  delete parser;
503  XMLPlatformUtils::Terminate();
504  return false;
505  }
506  catch ( ... )
507  {
508  Logger::log() << Logger::Error << "General System Exception !" << Logger::endl;
509  delete parser;
510  XMLPlatformUtils::Terminate();
511  return false;
512  }
513  return true;
514  }
515 }
516 
517 #endif
518 
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:51
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