00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "TinyDemarshaller.hpp"
00040
00041
00042
00043
00044 #include "tinyxml.h"
00045
00046
00047 #ifdef TIXML_USE_STL
00048 #include <iostream>
00049 #include <sstream>
00050 using namespace std;
00051 #else
00052 #include <cstdio>
00053 #endif
00054
00055 #include <stack>
00056 #include <Property.hpp>
00057 #include <PropertyBag.hpp>
00058 #include <Logger.hpp>
00059
00060 namespace RTT
00061 {
00062 namespace marsh
00063 {
00064 class Tiny2CPFHandler
00065 {
00069 PropertyBag &bag;
00070 std::stack< std::pair<PropertyBag*, Property<PropertyBag>*> > bag_stack;
00071
00072 enum Tag { TAG_STRUCT, TAG_SIMPLE, TAG_SEQUENCE, TAG_PROPERTIES, TAG_DESCRIPTION, TAG_VALUE, TAG_UNKNOWN};
00073 std::stack<Tag> tag_stack;
00074
00078 std::string name;
00079 std::string description;
00080 std::string type;
00081 std::string value_string;
00082
00083 public:
00084
00085 Tiny2CPFHandler( PropertyBag &b ) : bag( b )
00086 {
00087 Property<PropertyBag>* dummy = 0;
00088 bag_stack.push(std::make_pair(&bag, dummy));
00089 }
00090
00091 bool endElement()
00092 {
00093 switch ( tag_stack.top() )
00094 {
00095 case TAG_SIMPLE:
00096 if ( type == "boolean" )
00097 {
00098 if ( value_string == "1" || value_string == "true")
00099 bag_stack.top().first->add
00100 ( new Property<bool>( name, description, true ) );
00101 else if ( value_string == "0" || value_string == "false")
00102 bag_stack.top().first->add
00103 ( new Property<bool>( name, description, false ) );
00104 else {
00105 log(Error)<< "Wrong value for property '"+type+"'." \
00106 " Value should contain '0' or '1', got '"+ value_string +"'." << endlog();
00107 return false;
00108 }
00109 }
00110 else if ( type == "char" ) {
00111 if ( value_string.length() > 1 ) {
00112 log(Error) << "Wrong value for property '"+type+"'." \
00113 " Value should contain a single character, got '"+ value_string +"'." << endlog();
00114 return false;
00115 }
00116 else
00117 bag_stack.top().first->add
00118 ( new Property<char>( name, description, value_string.empty() ? '\0' : value_string[0] ) );
00119 }
00120 else if ( type == "uchar" || type == "octet" ) {
00121 if ( value_string.length() > 1 ) {
00122 log(Error) << "Wrong value for property '"+type+"'." \
00123 " Value should contain a single unsigned character, got '"+ value_string +"'." << endlog();
00124 return false;
00125 }
00126 else
00127 bag_stack.top().first->add
00128 ( new Property<unsigned char>( name, description, value_string.empty() ? '\0' : value_string[0] ) );
00129 }
00130 else if ( type == "long" || type == "short")
00131 {
00132 if (type == "short") {
00133 log(Warning) << "Use type='long' instead of type='short' for Property '"<< name << "', since 16bit integers are not supported." <<endlog();
00134 log(Warning) << "Future versions of RTT will no longer map XML 'short' to C++ 'int' but to C++ 'short' Property objects." <<endlog();
00135 }
00136 int v;
00137 if ( sscanf(value_string.c_str(), "%d", &v) == 1)
00138 bag_stack.top().first->add( new Property<int>( name, description, v ) );
00139 else {
00140 log(Error) << "Wrong value for property '"+type+"'." \
00141 " Value should contain an integer value, got '"+ value_string +"'." << endlog();
00142 return false;
00143 }
00144 }
00145 else if ( type == "ulong" || type == "ushort")
00146 {
00147 if (type == "ushort") {
00148 log(Warning) << "Use type='ulong' instead of type='ushort' for Property '"<< name << "', since 16bit integers are not supported." <<endlog();
00149 log(Warning) << "Future versions of RTT will no longer map XML 'ushort' to C++ 'unsigned int' but to C++ 'unsigned short' Property objects." <<endlog();
00150 }
00151 unsigned int v;
00152 if ( sscanf(value_string.c_str(), "%u", &v) == 1)
00153 bag_stack.top().first->add( new Property<unsigned int>( name, description, v ) );
00154 else {
00155 log(Error) << "Wrong value for property '"+type+"'." \
00156 " Value should contain an integer value, got '"+ value_string +"'." << endlog();
00157 return false;
00158 }
00159 }
00160 else if ( type == "double")
00161 {
00162 double v;
00163 if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
00164 bag_stack.top().first->add
00165 ( new Property<double>( name, description, v ) );
00166 else {
00167 log(Error) << "Wrong value for property '"+type+"'." \
00168 " Value should contain a double value, got '"+ value_string +"'." << endlog();
00169 return false;
00170 }
00171 }
00172 else if ( type == "float")
00173 {
00174 float v;
00175 if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
00176 bag_stack.top().first->add
00177 ( new Property<float>( name, description, v ) );
00178 else {
00179 log(Error) << "Wrong value for property '"+type+"'." \
00180 " Value should contain a float value, got '"+ value_string +"'." << endlog();
00181 return false;
00182 }
00183 }
00184 else if ( type == "string")
00185 bag_stack.top().first->add
00186 ( new Property<std::string>( name, description, value_string ) );
00187 tag_stack.pop();
00188 value_string.clear();
00189 description.clear();
00190 name.clear();
00191 break;
00192
00193 case TAG_SEQUENCE:
00194 case TAG_STRUCT:
00195 {
00196 Property<PropertyBag>* prop = bag_stack.top().second;
00197 bag_stack.pop();
00198 bag_stack.top().first->add( prop );
00199
00200
00201 tag_stack.pop();
00202 description.clear();
00203 name.clear();
00204 type.clear();
00205 }
00206 break;
00207
00208 case TAG_DESCRIPTION:
00209 tag_stack.pop();
00210 if ( tag_stack.top() == TAG_STRUCT ) {
00211
00212 bag_stack.top().second->setDescription(description);
00213 description.clear();
00214 }
00215 break;
00216 case TAG_VALUE:
00217 case TAG_PROPERTIES:
00218 case TAG_UNKNOWN:
00219 tag_stack.pop();
00220 break;
00221
00222 }
00223 return true;
00224 }
00225
00226
00227 void startElement(const char* localname,
00228 const TiXmlAttribute* attributes )
00229 {
00230 std::string ln = localname;
00231
00232 if ( ln == "properties" )
00233 tag_stack.push( TAG_PROPERTIES );
00234 else
00235 if ( ln == "simple" )
00236 {
00237 tag_stack.push( TAG_SIMPLE );
00238 name.clear();
00239 type.clear();
00240 while (attributes)
00241 {
00242 std::string an = attributes->Name();
00243 if ( an == "name")
00244 {
00245 name = attributes->Value();
00246 }
00247 else if ( an == "type")
00248 {
00249 type = attributes->Value();
00250 }
00251 attributes = attributes->Next();
00252 }
00253 }
00254 else
00255 if ( ln == "struct" || ln == "sequence")
00256 {
00257 name.clear();
00258 type.clear();
00259 while (attributes)
00260 {
00261 std::string an = attributes->Name();
00262 if ( an == "name")
00263 {
00264 name = attributes->Value();
00265 }
00266 else if ( an == "type")
00267 {
00268 type = attributes->Value();
00269 }
00270 attributes = attributes->Next();
00271 }
00272 if ( ln == "struct" )
00273 tag_stack.push( TAG_STRUCT );
00274 else {
00275 tag_stack.push( TAG_SEQUENCE );
00276 type = "Sequence";
00277 }
00278
00279 Property<PropertyBag> *prop;
00280 prop = new Property<PropertyBag>(name,"",PropertyBag(type));
00281
00282
00283 bag_stack.push(std::make_pair( &(prop->value()), prop));
00284 }
00285 else
00286 if ( ln == "description")
00287 tag_stack.push( TAG_DESCRIPTION );
00288 else
00289 if ( ln == "value" )
00290 tag_stack.push( TAG_VALUE );
00291 else {
00292 log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
00293 tag_stack.push( TAG_UNKNOWN );
00294 }
00295 }
00296
00297 void characters( const char* chars )
00298 {
00299 switch ( tag_stack.top() )
00300 {
00301 case TAG_DESCRIPTION:
00302 description = chars;
00303 break;
00304
00305 case TAG_VALUE:
00306 value_string = chars;;
00307 break;
00308 case TAG_STRUCT:
00309 case TAG_SIMPLE:
00310 case TAG_SEQUENCE:
00311 case TAG_PROPERTIES:
00312 case TAG_UNKNOWN:
00313 break;
00314 }
00315 }
00316
00317 bool populateBag(TiXmlNode* pParent)
00318 {
00319 if ( !pParent )
00320 return false;
00321
00322 TiXmlNode* pChild;
00323 TiXmlText* pText;
00324 int t = pParent->Type();
00325
00326 switch ( t )
00327 {
00328 case TiXmlNode::ELEMENT:
00329
00330 this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() );
00331
00332
00333 for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
00334 {
00335 if ( this->populateBag( pChild ) == false)
00336 return false;
00337 }
00338
00339
00340 if ( this->endElement() == false )
00341 return false;
00342 break;
00343
00344 case TiXmlNode::TEXT:
00345 pText = pParent->ToText();
00346 this->characters( pText->Value() );
00347 break;
00348
00349
00350 case TiXmlNode::DECLARATION:
00351 case TiXmlNode::COMMENT:
00352 case TiXmlNode::UNKNOWN:
00353 case TiXmlNode::DOCUMENT:
00354 default:
00355 break;
00356 }
00357 return true;
00358 }
00359 };
00360 }
00361
00362 using namespace detail;
00363
00364 class TinyDemarshaller::D {
00365 public:
00366 D(const std::string& f) : doc( f.c_str() ), loadOkay(false) {}
00367 TiXmlDocument doc;
00368 bool loadOkay;
00369 };
00370
00371 TinyDemarshaller::TinyDemarshaller( const std::string& filename )
00372 : d( new TinyDemarshaller::D(filename) )
00373 {
00374 Logger::In in("TinyDemarshaller");
00375 d->loadOkay = d->doc.LoadFile();
00376
00377 if ( !d->loadOkay ) {
00378 log(Error) << "Could not load " << filename << " Error: "<< d->doc.ErrorDesc() << endlog();
00379 return;
00380 }
00381
00382 }
00383
00384 TinyDemarshaller::~TinyDemarshaller()
00385 {
00386 delete d;
00387 }
00388
00389 bool TinyDemarshaller::deserialize( PropertyBag &v )
00390 {
00391 Logger::In in("TinyDemarshaller");
00392
00393 if ( !d->loadOkay )
00394 return false;
00395
00396 TiXmlHandle docHandle( &d->doc );
00397 TiXmlHandle propHandle = docHandle.FirstChildElement( "properties" );
00398
00399 if ( ! propHandle.Node() ) {
00400 log(Error) << "No <properties> element found in document!"<< endlog();
00401 return false;
00402 }
00403
00404 detail::Tiny2CPFHandler proc( v );
00405
00406 if ( proc.populateBag( propHandle.Node() ) == false) {
00407 deleteProperties( v );
00408 return false;
00409 }
00410 return true;
00411 }
00412
00413 }
00414