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" )
00099 bag_stack.top().first->add
00100 ( new Property<bool>( name, description, true ) );
00101 else if ( value_string == "0" )
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" ) {
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 int v;
00133 if ( sscanf(value_string.c_str(), "%d", &v) == 1)
00134 bag_stack.top().first->add( new Property<int>( name, description, v ) );
00135 else {
00136 log(Error) << "Wrong value for property '"+type+"'." \
00137 " Value should contain an integer value, got '"+ value_string +"'." << endlog();
00138 return false;
00139 }
00140 }
00141 else if ( type == "ulong" || type == "ushort")
00142 {
00143 unsigned int v;
00144 if ( sscanf(value_string.c_str(), "%u", &v) == 1)
00145 bag_stack.top().first->add( new Property<unsigned int>( name, description, v ) );
00146 else {
00147 log(Error) << "Wrong value for property '"+type+"'." \
00148 " Value should contain an integer value, got '"+ value_string +"'." << endlog();
00149 return false;
00150 }
00151 }
00152 else if ( type == "double")
00153 {
00154 double v;
00155 if ( sscanf(value_string.c_str(), "%lf", &v) == 1 )
00156 bag_stack.top().first->add
00157 ( new Property<double>( name, description, v ) );
00158 else {
00159 log(Error) << "Wrong value for property '"+type+"'." \
00160 " Value should contain a double value, got '"+ value_string +"'." << endlog();
00161 return false;
00162 }
00163 }
00164 else if ( type == "float")
00165 {
00166 float v;
00167 if ( sscanf(value_string.c_str(), "%f", &v) == 1 )
00168 bag_stack.top().first->add
00169 ( new Property<float>( name, description, v ) );
00170 else {
00171 log(Error) << "Wrong value for property '"+type+"'." \
00172 " Value should contain a float value, got '"+ value_string +"'." << endlog();
00173 return false;
00174 }
00175 }
00176 else if ( type == "string")
00177 bag_stack.top().first->add
00178 ( new Property<std::string>( name, description, value_string ) );
00179 tag_stack.pop();
00180 value_string.clear();
00181 description.clear();
00182 name.clear();
00183 break;
00184
00185 case TAG_SEQUENCE:
00186 case TAG_STRUCT:
00187 {
00188 Property<PropertyBag>* prop = bag_stack.top().second;
00189 bag_stack.pop();
00190 bag_stack.top().first->add( prop );
00191
00192
00193 tag_stack.pop();
00194 description.clear();
00195 name.clear();
00196 type.clear();
00197 }
00198 break;
00199
00200 case TAG_DESCRIPTION:
00201 tag_stack.pop();
00202 if ( tag_stack.top() == TAG_STRUCT ) {
00203
00204 bag_stack.top().second->setDescription(description);
00205 description.clear();
00206 }
00207 break;
00208 case TAG_VALUE:
00209 case TAG_PROPERTIES:
00210 case TAG_UNKNOWN:
00211 tag_stack.pop();
00212 break;
00213
00214 }
00215 return true;
00216 }
00217
00218
00219 void startElement(const char* localname,
00220 const TiXmlAttribute* attributes )
00221 {
00222 std::string ln = localname;
00223
00224 if ( ln == "properties" )
00225 tag_stack.push( TAG_PROPERTIES );
00226 else
00227 if ( ln == "simple" )
00228 {
00229 tag_stack.push( TAG_SIMPLE );
00230 name.clear();
00231 type.clear();
00232 while (attributes)
00233 {
00234 std::string an = attributes->Name();
00235 if ( an == "name")
00236 {
00237 name = attributes->Value();
00238 }
00239 else if ( an == "type")
00240 {
00241 type = attributes->Value();
00242 }
00243 attributes = attributes->Next();
00244 }
00245 }
00246 else
00247 if ( ln == "struct" || ln == "sequence")
00248 {
00249 name.clear();
00250 type.clear();
00251 while (attributes)
00252 {
00253 std::string an = attributes->Name();
00254 if ( an == "name")
00255 {
00256 name = attributes->Value();
00257 }
00258 else if ( an == "type")
00259 {
00260 type = attributes->Value();
00261 }
00262 attributes = attributes->Next();
00263 }
00264 if ( ln == "struct" )
00265 tag_stack.push( TAG_STRUCT );
00266 else {
00267 tag_stack.push( TAG_SEQUENCE );
00268 type = "Sequence";
00269 }
00270
00271 Property<PropertyBag> *prop;
00272 prop = new Property<PropertyBag>(name,"",PropertyBag(type));
00273
00274
00275 bag_stack.push(std::make_pair( &(prop->value()), prop));
00276 }
00277 else
00278 if ( ln == "description")
00279 tag_stack.push( TAG_DESCRIPTION );
00280 else
00281 if ( ln == "value" )
00282 tag_stack.push( TAG_VALUE );
00283 else {
00284 log(Warning) << "Unrecognised XML tag :"<< ln <<": ignoring." << endlog();
00285 tag_stack.push( TAG_UNKNOWN );
00286 }
00287 }
00288
00289 void characters( const char* chars )
00290 {
00291 switch ( tag_stack.top() )
00292 {
00293 case TAG_DESCRIPTION:
00294 description = chars;
00295 break;
00296
00297 case TAG_VALUE:
00298 value_string = chars;;
00299 break;
00300 case TAG_STRUCT:
00301 case TAG_SIMPLE:
00302 case TAG_SEQUENCE:
00303 case TAG_PROPERTIES:
00304 case TAG_UNKNOWN:
00305 break;
00306 }
00307 }
00308
00309 bool populateBag(TiXmlNode* pParent)
00310 {
00311 if ( !pParent )
00312 return false;
00313
00314 TiXmlNode* pChild;
00315 TiXmlText* pText;
00316 int t = pParent->Type();
00317
00318 switch ( t )
00319 {
00320 case TiXmlNode::ELEMENT:
00321
00322 this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() );
00323
00324
00325 for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
00326 {
00327 if ( this->populateBag( pChild ) == false)
00328 return false;
00329 }
00330
00331
00332 if ( this->endElement() == false )
00333 return false;
00334 break;
00335
00336 case TiXmlNode::TEXT:
00337 pText = pParent->ToText();
00338 this->characters( pText->Value() );
00339 break;
00340
00341
00342 case TiXmlNode::DECLARATION:
00343 case TiXmlNode::COMMENT:
00344 case TiXmlNode::UNKNOWN:
00345 case TiXmlNode::DOCUMENT:
00346 default:
00347 break;
00348 }
00349 return true;
00350 }
00351 };
00352 }
00353
00354 using namespace detail;
00355
00356 class TinyDemarshaller::D {
00357 public:
00358 D(const std::string& f) : doc( f.c_str() ), loadOkay(false) {}
00359 TiXmlDocument doc;
00360 bool loadOkay;
00361 };
00362
00363 TinyDemarshaller::TinyDemarshaller( const std::string& filename )
00364 : d( new TinyDemarshaller::D(filename) )
00365 {
00366 Logger::In in("TinyDemarshaller");
00367 d->loadOkay = d->doc.LoadFile();
00368
00369 if ( !d->loadOkay ) {
00370 log(Error) << "Could not load " << filename << " Error: "<< d->doc.ErrorDesc() << endlog();
00371 return;
00372 }
00373
00374 }
00375
00376 TinyDemarshaller::~TinyDemarshaller()
00377 {
00378 delete d;
00379 }
00380
00381 bool TinyDemarshaller::deserialize( PropertyBag &v )
00382 {
00383 Logger::In in("TinyDemarshaller");
00384
00385 if ( !d->loadOkay )
00386 return false;
00387
00388 TiXmlHandle docHandle( &d->doc );
00389 TiXmlHandle propHandle = docHandle.FirstChildElement( "properties" );
00390
00391 if ( ! propHandle.Node() ) {
00392 log(Error) << "No <properties> element found in document!"<< endlog();
00393 return false;
00394 }
00395
00396 detail::Tiny2CPFHandler proc( v );
00397
00398 if ( proc.populateBag( propHandle.Node() ) == false) {
00399 deleteProperties( v );
00400 return false;
00401 }
00402 return true;
00403 }
00404
00405 }
00406