Orocos Real-Time Toolkit  2.9.0
TinyDemarshaller.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: FMTC Tue Mar 11 21:49:20 CET 2008 TinyDemarshaller.cpp
3 
4  TinyDemarshaller.cpp - description
5  -------------------
6  begin : Tue March 11 2008
7  copyright : (C) 2008 FMTC
8  email : peter.soetens@fmtc.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 #include "TinyDemarshaller.hpp"
40 
41 
42 // Modified tinyxml* to include it in the RTT namespace to avoid clashes
43 // with possible other libraries.
44 #include "tinyxml.h"
45 
46 // This is currently not defined:
47 #ifdef TIXML_USE_STL
48 #include <iostream>
49 #include <sstream>
50 using namespace std;
51 #else
52 #include <cstdio>
53 #endif
54 
55 #include <stack>
56 #include <Property.hpp>
57 #include <PropertyBag.hpp>
58 #include <Logger.hpp>
59 
60 namespace RTT
61 {
62  namespace marsh
63  {
65  {
69  PropertyBag &bag;
70  std::stack< std::pair<PropertyBag*, Property<PropertyBag>*> > bag_stack;
71 
72  enum Tag { TAG_STRUCT, TAG_SIMPLE, TAG_SEQUENCE, TAG_PROPERTIES, TAG_DESCRIPTION, TAG_VALUE, TAG_UNKNOWN};
73  std::stack<Tag> tag_stack;
74 
78  std::string name;
79  std::string description;
80  std::string type;
81  std::string value_string;
82 
83  public:
84 
85  Tiny2CPFHandler( PropertyBag &b ) : bag( b )
86  {
87  Property<PropertyBag>* dummy = 0;
88  bag_stack.push(std::make_pair(&bag, dummy));
89  }
90 
91  bool endElement()
92  {
93  switch ( tag_stack.top() )
94  {
95  case TAG_SIMPLE:
96  if ( type == "boolean" )
97  {
98  if ( value_string == "1" || value_string == "true")
99  bag_stack.top().first->add
100  ( new Property<bool>( name, description, true ) );
101  else if ( value_string == "0" || value_string == "false")
102  bag_stack.top().first->add
103  ( new Property<bool>( name, description, false ) );
104  else {
105  log(Error)<< "Wrong value for property '"+type+"'." \
106  " Value should contain '0' or '1', got '"+ value_string +"'." << endlog();
107  return false;
108  }
109  }
110  else if ( type == "char" ) {
111  if ( value_string.length() > 1 ) {
112  log(Error) << "Wrong value for property '"+type+"'." \
113  " Value should contain a single character, got '"+ value_string +"'." << endlog();
114  return false;
115  }
116  else
117  bag_stack.top().first->add
118  ( new Property<char>( name, description, value_string.empty() ? '\0' : value_string[0] ) );
119  }
120  else if ( type == "uchar" || type == "octet" ) {
121  if ( value_string.length() > 1 ) {
122  log(Error) << "Wrong value for property '"+type+"'." \
123  " Value should contain a single unsigned character, got '"+ value_string +"'." << endlog();
124  return false;
125  }
126  else
127  bag_stack.top().first->add
128  ( new Property<unsigned char>( name, description, value_string.empty() ? '\0' : value_string[0] ) );
129  }
130  else if ( type == "long" || type == "short")
131  {
132  if (type == "short") {
133  log(Warning) << "Use type='long' instead of type='short' for Property '"<< name << "', since 16bit integers are not supported." <<endlog();
134  log(Warning) << "Future versions of RTT will no longer map XML 'short' to C++ 'int' but to C++ 'short' Property objects." <<endlog();
135  }
136  int v;
137  if ( sscanf(value_string.c_str(), "%d", &v) == 1)
138  bag_stack.top().first->add( new Property<int>( name, description, v ) );
139  else {
140  log(Error) << "Wrong value for property '"+type+"'." \
141  " Value should contain an integer value, got '"+ value_string +"'." << endlog();
142  return false;
143  }
144  }
145  else if ( type == "ulong" || type == "ushort")
146  {
147  if (type == "ushort") {
148  log(Warning) << "Use type='ulong' instead of type='ushort' for Property '"<< name << "', since 16bit integers are not supported." <<endlog();
149  log(Warning) << "Future versions of RTT will no longer map XML 'ushort' to C++ 'unsigned int' but to C++ 'unsigned short' Property objects." <<endlog();
150  }
151  unsigned int v;
152  if ( sscanf(value_string.c_str(), "%u", &v) == 1)
153  bag_stack.top().first->add( new Property<unsigned int>( name, description, v ) );
154  else {
155  log(Error) << "Wrong value for property '"+type+"'." \
156  " Value should contain an integer value, got '"+ value_string +"'." << endlog();
157  return false;
158  }
159  }
160  else if ( type == "llong")
161  {
162  long long v;
163  if ( sscanf(value_string.c_str(), "%lld", &v) == 1)
164  bag_stack.top().first->add( new Property<long long>( name, description, v ) );
165  else {
166  log(Error) << "Wrong value for property '"+type+"'." \
167  " Value should contain an integer value, got '"+ value_string +"'." << endlog();
168  return false;
169  }
170  }
171  else if ( type == "ullong")
172  {
173  unsigned long long v;
174  if ( sscanf(value_string.c_str(), "%llu", &v) == 1)
175  bag_stack.top().first->add( new Property<unsigned long long>( name, description, v ) );
176  else {
177  log(Error) << "Wrong value for property '"+type+"'." \
178  " Value should contain an integer value, got '"+ value_string +"'." << endlog();
179  return false;
180  }
181  }
182  else if ( type == "double")
183  {
184  double v;
185  if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
186  bag_stack.top().first->add
187  ( new Property<double>( name, description, v ) );
188  else {
189  log(Error) << "Wrong value for property '"+type+"'." \
190  " Value should contain a double value, got '"+ value_string +"'." << endlog();
191  return false;
192  }
193  }
194  else if ( type == "float")
195  {
196  float v;
197  if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
198  bag_stack.top().first->add
199  ( new Property<float>( name, description, v ) );
200  else {
201  log(Error) << "Wrong value for property '"+type+"'." \
202  " Value should contain a float value, got '"+ value_string +"'." << endlog();
203  return false;
204  }
205  }
206  else if ( type == "string")
207  bag_stack.top().first->add
208  ( new Property<std::string>( name, description, value_string ) );
209  else{
210  log(Error)<<"Unknown type \""<<type<< "\" for for tag simple"<<endlog();
211  return false;
212  }
213  tag_stack.pop();
214  value_string.clear(); // cleanup
215  description.clear();
216  name.clear();
217  break;
218 
219  case TAG_SEQUENCE:
220  case TAG_STRUCT:
221  {
222  Property<PropertyBag>* prop = bag_stack.top().second;
223  bag_stack.pop();
224  bag_stack.top().first->add( prop );
225  //( new Property<PropertyBag>( pn, description, *pb ) );
226  //delete pb;
227  tag_stack.pop();
228  description.clear();
229  name.clear();
230  type.clear();
231  }
232  break;
233 
234  case TAG_DESCRIPTION:
235  tag_stack.pop();
236  if ( tag_stack.top() == TAG_STRUCT ) {
237  // it is a description of a struct that ended
238  bag_stack.top().second->setDescription(description);
239  description.clear();
240  }
241  break;
242  case TAG_VALUE:
243  case TAG_PROPERTIES:
244  case TAG_UNKNOWN:
245  tag_stack.pop();
246  break;
247 
248  }
249  return true;
250  }
251 
252 
253  void startElement(const char* localname,
254  const TiXmlAttribute* attributes )
255  {
256  std::string ln = localname;
257 
258  if ( ln == "properties" )
259  tag_stack.push( TAG_PROPERTIES );
260  else
261  if ( ln == "simple" )
262  {
263  tag_stack.push( TAG_SIMPLE );
264  name.clear();
265  type.clear();
266  while (attributes)
267  {
268  std::string an = attributes->Name();
269  if ( an == "name")
270  {
271  name = attributes->Value();
272  }
273  else if ( an == "type")
274  {
275  type = attributes->Value();
276  }
277  attributes = attributes->Next();
278  }
279  }
280  else
281  if ( ln == "struct" || ln == "sequence")
282  {
283  name.clear();
284  type.clear();
285  while (attributes)
286  {
287  std::string an = attributes->Name();
288  if ( an == "name")
289  {
290  name = attributes->Value();
291  }
292  else if ( an == "type")
293  {
294  type = attributes->Value();
295  }
296  attributes = attributes->Next();
297  }
298  if ( ln == "struct" )
299  tag_stack.push( TAG_STRUCT );
300  else {
301  tag_stack.push( TAG_SEQUENCE );
302  type = "Sequence"; // override
303  }
304 
305  Property<PropertyBag> *prop;
306  prop = new Property<PropertyBag>(name,"",PropertyBag(type));
307 
308  // take reference to bag itself !
309  bag_stack.push(std::make_pair( &(prop->value()), prop));
310  }
311  else
312  if ( ln == "description")
313  tag_stack.push( TAG_DESCRIPTION );
314  else
315  if ( ln == "value" )
316  tag_stack.push( TAG_VALUE );
317  else {
318  log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
319  tag_stack.push( TAG_UNKNOWN );
320  }
321  }
322 
323  void characters( const char* chars )
324  {
325  switch ( tag_stack.top() )
326  {
327  case TAG_DESCRIPTION:
328  description = chars;
329  break;
330 
331  case TAG_VALUE:
332  value_string = chars;;
333  break;
334  case TAG_STRUCT:
335  case TAG_SIMPLE:
336  case TAG_SEQUENCE:
337  case TAG_PROPERTIES:
338  case TAG_UNKNOWN:
339  break;
340  }
341  }
342 
343  bool populateBag(TiXmlNode* pParent)
344  {
345  if ( !pParent )
346  return false;
347 
348  TiXmlNode* pChild;
349  TiXmlText* pText;
350  int t = pParent->Type();
351 
352  switch ( t )
353  {
354  case TiXmlNode::ELEMENT:
355  // notify start of new element
356  this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() );
357 
358  // recurse in children, if any
359  for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
360  {
361  if ( this->populateBag( pChild ) == false){
362  log(Error)<<"Error in element at line "<<pChild->Row() << endlog();
363  return false;
364  }
365  }
366 
367  // notify end of element
368  if ( this->endElement() == false )
369  return false;
370  break;
371 
372  case TiXmlNode::TEXT:
373  pText = pParent->ToText();
374  this->characters( pText->Value() );
375  break;
376 
377  // not interested in these...
378  case TiXmlNode::DECLARATION:
379  case TiXmlNode::COMMENT:
380  case TiXmlNode::UNKNOWN:
381  case TiXmlNode::DOCUMENT:
382  default:
383  break;
384  }
385  return true;
386  }
387  };
388  }
389 
390  using namespace detail;
391 
393  public:
394  D(const std::string& f) : doc( f.c_str() ), loadOkay(false) {}
396  bool loadOkay;
397  };
398 
399  TinyDemarshaller::TinyDemarshaller( const std::string& filename )
400  : d( new TinyDemarshaller::D(filename) )
401  {
402  Logger::In in("TinyDemarshaller");
403  d->loadOkay = d->doc.LoadFile();
404 
405  if ( !d->loadOkay ) {
406  log(Error) << "Could not load " << filename << " Error: "<< d->doc.ErrorDesc() << endlog();
407  return;
408  }
409 
410  }
411 
413  {
414  delete d;
415  }
416 
418  {
419  Logger::In in("TinyDemarshaller");
420 
421  if ( !d->loadOkay )
422  return false;
423 
424  TiXmlHandle docHandle( &d->doc );
425  TiXmlHandle propHandle = docHandle.FirstChildElement( "properties" );
426 
427  if ( ! propHandle.Node() ) {
428  log(Error) << "No <properties> element found in document!"<< endlog();
429  return false;
430  }
431 
432  detail::Tiny2CPFHandler proc( v );
433 
434  if ( proc.populateBag( propHandle.Node() ) == false) {
435  deleteProperties( v );
436  return false;
437  }
438  return true;
439  }
440 
441 }
442 
A TiXmlHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thi...
Definition: tinyxml.h:1497
const TiXmlAttribute * Next() const
Get the next sibling attribute in the DOM. Returns null at end.
Definition: tinyxml.cpp:1268
const char * Name() const
Return the name of this attribute.
Definition: tinyxml.h:765
bool populateBag(TiXmlNode *pParent)
const char * Value() const
Return the value of this attribute.
Definition: tinyxml.h:766
int Type() const
Query the type (as an enumerated value, above) of this node.
Definition: tinyxml.h:664
virtual const TiXmlText * ToText() const
Cast to a more defined type. Will return null if not of the requested type.
Definition: tinyxml.h:679
const TiXmlNode * FirstChild() const
The first child of this node. Will be null if there are no children.
Definition: tinyxml.h:525
const TiXmlAttribute * FirstAttribute() const
Access the first attribute in this element.
Definition: tinyxml.h:971
STL namespace.
An attribute is a name-value pair.
Definition: tinyxml.h:733
Always the top level node.
Definition: tinyxml.h:1259
TiXmlHandle FirstChildElement() const
Return a handle to the first child element.
Definition: tinyxml.cpp:1741
A container for holding references to properties.
Definition: PropertyBag.hpp:96
TiXmlNode * Node() const
Return the handle as a TiXmlNode. This may return null.
Definition: tinyxml.h:1543
reference_t value()
Access to the value of the Property.
Definition: Property.hpp:277
void characters(const char *chars)
A property represents a named value of any type with a description.
Definition: Property.hpp:76
virtual bool deserialize(PropertyBag &v)
Deserialize data to a property bag.
The parent class for everything in the Document Object Model.
Definition: tinyxml.h:425
void deleteProperties(PropertyBag &target)
This function iterates over a PropertyBag and deletes all Property objects in it without recursion...
Notify the Logger in which &#39;module&#39; the message occured.
Definition: Logger.hpp:159
A TinyXML demarshaller for extracting properties and property bags from a Component Property File (CP...
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
virtual const TiXmlElement * ToElement() const
Cast to a more defined type. Will return null if not of the requested type.
Definition: tinyxml.h:676
const char * Value() const
The meaning of &#39;value&#39; changes for the specific type of TiXmlNode.
Definition: tinyxml.h:492
const TiXmlNode * NextSibling() const
Navigate to a sibling node.
Definition: tinyxml.h:621
void startElement(const char *localname, const TiXmlAttribute *attributes)
D(const std::string &f)
int Row() const
Return the position, in the original source file, of this node or attribute.
Definition: tinyxml.h:235