Orocos Real-Time Toolkit  2.8.3
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 == "double")
161  {
162  double v;
163  if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
164  bag_stack.top().first->add
165  ( new Property<double>( name, description, v ) );
166  else {
167  log(Error) << "Wrong value for property '"+type+"'." \
168  " Value should contain a double value, got '"+ value_string +"'." << endlog();
169  return false;
170  }
171  }
172  else if ( type == "float")
173  {
174  float v;
175  if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
176  bag_stack.top().first->add
177  ( new Property<float>( name, description, v ) );
178  else {
179  log(Error) << "Wrong value for property '"+type+"'." \
180  " Value should contain a float value, got '"+ value_string +"'." << endlog();
181  return false;
182  }
183  }
184  else if ( type == "string")
185  bag_stack.top().first->add
186  ( new Property<std::string>( name, description, value_string ) );
187  else{
188  log(Error)<<"Unknown type \""<<type<< "\" for for tag simple"<<endlog();
189  return false;
190  }
191  tag_stack.pop();
192  value_string.clear(); // cleanup
193  description.clear();
194  name.clear();
195  break;
196 
197  case TAG_SEQUENCE:
198  case TAG_STRUCT:
199  {
200  Property<PropertyBag>* prop = bag_stack.top().second;
201  bag_stack.pop();
202  bag_stack.top().first->add( prop );
203  //( new Property<PropertyBag>( pn, description, *pb ) );
204  //delete pb;
205  tag_stack.pop();
206  description.clear();
207  name.clear();
208  type.clear();
209  }
210  break;
211 
212  case TAG_DESCRIPTION:
213  tag_stack.pop();
214  if ( tag_stack.top() == TAG_STRUCT ) {
215  // it is a description of a struct that ended
216  bag_stack.top().second->setDescription(description);
217  description.clear();
218  }
219  break;
220  case TAG_VALUE:
221  case TAG_PROPERTIES:
222  case TAG_UNKNOWN:
223  tag_stack.pop();
224  break;
225 
226  }
227  return true;
228  }
229 
230 
231  void startElement(const char* localname,
232  const TiXmlAttribute* attributes )
233  {
234  std::string ln = localname;
235 
236  if ( ln == "properties" )
237  tag_stack.push( TAG_PROPERTIES );
238  else
239  if ( ln == "simple" )
240  {
241  tag_stack.push( TAG_SIMPLE );
242  name.clear();
243  type.clear();
244  while (attributes)
245  {
246  std::string an = attributes->Name();
247  if ( an == "name")
248  {
249  name = attributes->Value();
250  }
251  else if ( an == "type")
252  {
253  type = attributes->Value();
254  }
255  attributes = attributes->Next();
256  }
257  }
258  else
259  if ( ln == "struct" || ln == "sequence")
260  {
261  name.clear();
262  type.clear();
263  while (attributes)
264  {
265  std::string an = attributes->Name();
266  if ( an == "name")
267  {
268  name = attributes->Value();
269  }
270  else if ( an == "type")
271  {
272  type = attributes->Value();
273  }
274  attributes = attributes->Next();
275  }
276  if ( ln == "struct" )
277  tag_stack.push( TAG_STRUCT );
278  else {
279  tag_stack.push( TAG_SEQUENCE );
280  type = "Sequence"; // override
281  }
282 
283  Property<PropertyBag> *prop;
284  prop = new Property<PropertyBag>(name,"",PropertyBag(type));
285 
286  // take reference to bag itself !
287  bag_stack.push(std::make_pair( &(prop->value()), prop));
288  }
289  else
290  if ( ln == "description")
291  tag_stack.push( TAG_DESCRIPTION );
292  else
293  if ( ln == "value" )
294  tag_stack.push( TAG_VALUE );
295  else {
296  log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
297  tag_stack.push( TAG_UNKNOWN );
298  }
299  }
300 
301  void characters( const char* chars )
302  {
303  switch ( tag_stack.top() )
304  {
305  case TAG_DESCRIPTION:
306  description = chars;
307  break;
308 
309  case TAG_VALUE:
310  value_string = chars;;
311  break;
312  case TAG_STRUCT:
313  case TAG_SIMPLE:
314  case TAG_SEQUENCE:
315  case TAG_PROPERTIES:
316  case TAG_UNKNOWN:
317  break;
318  }
319  }
320 
321  bool populateBag(TiXmlNode* pParent)
322  {
323  if ( !pParent )
324  return false;
325 
326  TiXmlNode* pChild;
327  TiXmlText* pText;
328  int t = pParent->Type();
329 
330  switch ( t )
331  {
332  case TiXmlNode::ELEMENT:
333  // notify start of new element
334  this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() );
335 
336  // recurse in children, if any
337  for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
338  {
339  if ( this->populateBag( pChild ) == false){
340  log(Error)<<"Error in element at line "<<pChild->Row() << endlog();
341  return false;
342  }
343  }
344 
345  // notify end of element
346  if ( this->endElement() == false )
347  return false;
348  break;
349 
350  case TiXmlNode::TEXT:
351  pText = pParent->ToText();
352  this->characters( pText->Value() );
353  break;
354 
355  // not interested in these...
356  case TiXmlNode::DECLARATION:
357  case TiXmlNode::COMMENT:
358  case TiXmlNode::UNKNOWN:
359  case TiXmlNode::DOCUMENT:
360  default:
361  break;
362  }
363  return true;
364  }
365  };
366 
367  using namespace detail;
368 
370  public:
371  D(const std::string& f) : doc( f.c_str() ), loadOkay(false) {}
373  bool loadOkay;
374  };
375 
376  TinyDemarshaller::TinyDemarshaller( const std::string& filename )
377  : d( new TinyDemarshaller::D(filename) )
378  {
379  Logger::In in("TinyDemarshaller");
380  d->loadOkay = d->doc.LoadFile();
381 
382  if ( !d->loadOkay ) {
383  log(Error) << "Could not load " << filename << " Error: "<< d->doc.ErrorDesc() << endlog();
384  return;
385  }
386 
387  }
388 
390  {
391  delete d;
392  }
393 
395  {
396  Logger::In in("TinyDemarshaller");
397 
398  if ( !d->loadOkay )
399  return false;
400 
401  TiXmlHandle docHandle( &d->doc );
402  TiXmlHandle propHandle = docHandle.FirstChildElement( "properties" );
403 
404  if ( ! propHandle.Node() ) {
405  log(Error) << "No <properties> element found in document!"<< endlog();
406  return false;
407  }
408 
409  detail::Tiny2CPFHandler proc( v );
410 
411  if ( proc.populateBag( propHandle.Node() ) == false) {
412  deleteProperties( v );
413  return false;
414  }
415  return true;
416  }
417 
418  }
419 }
420 
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
const char * ErrorDesc() const
Contains a textual (english) description of the error if one occurs.
Definition: tinyxml.h:1331
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
The parent class for everything in the Document Object Model.
Definition: tinyxml.h:425
virtual bool deserialize(PropertyBag &v)
Deserialize data to a property bag.
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:51
virtual const TiXmlElement * ToElement() const
Cast to a more defined type. Will return null if not of the requested type.
Definition: tinyxml.h:676
bool LoadFile(TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Load a file using the current document value.
Definition: tinyxml.cpp:1020
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)
int Row() const
Return the position, in the original source file, of this node or attribute.
Definition: tinyxml.h:235