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 else{
00188 log(Error)<<"Unknown type \""<<type<< "\" for for tag simple"<<endlog();
00189 return false;
00190 }
00191 tag_stack.pop();
00192 value_string.clear();
00193 description.clear();
00194 name.clear();
00195 break;
00196
00197 case TAG_SEQUENCE:
00198 case TAG_STRUCT:
00199 {
00200 Property<PropertyBag>* prop = bag_stack.top().second;
00201 bag_stack.pop();
00202 bag_stack.top().first->add( prop );
00203
00204
00205 tag_stack.pop();
00206 description.clear();
00207 name.clear();
00208 type.clear();
00209 }
00210 break;
00211
00212 case TAG_DESCRIPTION:
00213 tag_stack.pop();
00214 if ( tag_stack.top() == TAG_STRUCT ) {
00215
00216 bag_stack.top().second->setDescription(description);
00217 description.clear();
00218 }
00219 break;
00220 case TAG_VALUE:
00221 case TAG_PROPERTIES:
00222 case TAG_UNKNOWN:
00223 tag_stack.pop();
00224 break;
00225
00226 }
00227 return true;
00228 }
00229
00230
00231 void startElement(const char* localname,
00232 const TiXmlAttribute* attributes )
00233 {
00234 std::string ln = localname;
00235
00236 if ( ln == "properties" )
00237 tag_stack.push( TAG_PROPERTIES );
00238 else
00239 if ( ln == "simple" )
00240 {
00241 tag_stack.push( TAG_SIMPLE );
00242 name.clear();
00243 type.clear();
00244 while (attributes)
00245 {
00246 std::string an = attributes->Name();
00247 if ( an == "name")
00248 {
00249 name = attributes->Value();
00250 }
00251 else if ( an == "type")
00252 {
00253 type = attributes->Value();
00254 }
00255 attributes = attributes->Next();
00256 }
00257 }
00258 else
00259 if ( ln == "struct" || ln == "sequence")
00260 {
00261 name.clear();
00262 type.clear();
00263 while (attributes)
00264 {
00265 std::string an = attributes->Name();
00266 if ( an == "name")
00267 {
00268 name = attributes->Value();
00269 }
00270 else if ( an == "type")
00271 {
00272 type = attributes->Value();
00273 }
00274 attributes = attributes->Next();
00275 }
00276 if ( ln == "struct" )
00277 tag_stack.push( TAG_STRUCT );
00278 else {
00279 tag_stack.push( TAG_SEQUENCE );
00280 type = "Sequence";
00281 }
00282
00283 Property<PropertyBag> *prop;
00284 prop = new Property<PropertyBag>(name,"",PropertyBag(type));
00285
00286
00287 bag_stack.push(std::make_pair( &(prop->value()), prop));
00288 }
00289 else
00290 if ( ln == "description")
00291 tag_stack.push( TAG_DESCRIPTION );
00292 else
00293 if ( ln == "value" )
00294 tag_stack.push( TAG_VALUE );
00295 else {
00296 log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
00297 tag_stack.push( TAG_UNKNOWN );
00298 }
00299 }
00300
00301 void characters( const char* chars )
00302 {
00303 switch ( tag_stack.top() )
00304 {
00305 case TAG_DESCRIPTION:
00306 description = chars;
00307 break;
00308
00309 case TAG_VALUE:
00310 value_string = chars;;
00311 break;
00312 case TAG_STRUCT:
00313 case TAG_SIMPLE:
00314 case TAG_SEQUENCE:
00315 case TAG_PROPERTIES:
00316 case TAG_UNKNOWN:
00317 break;
00318 }
00319 }
00320
00321 bool populateBag(TiXmlNode* pParent)
00322 {
00323 if ( !pParent )
00324 return false;
00325
00326 TiXmlNode* pChild;
00327 TiXmlText* pText;
00328 int t = pParent->Type();
00329
00330 switch ( t )
00331 {
00332 case TiXmlNode::ELEMENT:
00333
00334 this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() );
00335
00336
00337 for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
00338 {
00339 if ( this->populateBag( pChild ) == false){
00340 log(Error)<<"Error in element at line "<<pChild->Row() << endlog();
00341 return false;
00342 }
00343 }
00344
00345
00346 if ( this->endElement() == false )
00347 return false;
00348 break;
00349
00350 case TiXmlNode::TEXT:
00351 pText = pParent->ToText();
00352 this->characters( pText->Value() );
00353 break;
00354
00355
00356 case TiXmlNode::DECLARATION:
00357 case TiXmlNode::COMMENT:
00358 case TiXmlNode::UNKNOWN:
00359 case TiXmlNode::DOCUMENT:
00360 default:
00361 break;
00362 }
00363 return true;
00364 }
00365 };
00366 }
00367
00368 using namespace detail;
00369
00370 class TinyDemarshaller::D {
00371 public:
00372 D(const std::string& f) : doc( f.c_str() ), loadOkay(false) {}
00373 TiXmlDocument doc;
00374 bool loadOkay;
00375 };
00376
00377 TinyDemarshaller::TinyDemarshaller( const std::string& filename )
00378 : d( new TinyDemarshaller::D(filename) )
00379 {
00380 Logger::In in("TinyDemarshaller");
00381 d->loadOkay = d->doc.LoadFile();
00382
00383 if ( !d->loadOkay ) {
00384 log(Error) << "Could not load " << filename << " Error: "<< d->doc.ErrorDesc() << endlog();
00385 return;
00386 }
00387
00388 }
00389
00390 TinyDemarshaller::~TinyDemarshaller()
00391 {
00392 delete d;
00393 }
00394
00395 bool TinyDemarshaller::deserialize( PropertyBag &v )
00396 {
00397 Logger::In in("TinyDemarshaller");
00398
00399 if ( !d->loadOkay )
00400 return false;
00401
00402 TiXmlHandle docHandle( &d->doc );
00403 TiXmlHandle propHandle = docHandle.FirstChildElement( "properties" );
00404
00405 if ( ! propHandle.Node() ) {
00406 log(Error) << "No <properties> element found in document!"<< endlog();
00407 return false;
00408 }
00409
00410 detail::Tiny2CPFHandler proc( v );
00411
00412 if ( proc.populateBag( propHandle.Node() ) == false) {
00413 deleteProperties( v );
00414 return false;
00415 }
00416 return true;
00417 }
00418
00419 }
00420