Orocos Real-Time Toolkit
2.5.0
|
00001 /*************************************************************************** 00002 tag: FMTC Tue Mar 11 21:49:20 CET 2008 TinyDemarshaller.cpp 00003 00004 TinyDemarshaller.cpp - description 00005 ------------------- 00006 begin : Tue March 11 2008 00007 copyright : (C) 2008 FMTC 00008 email : peter.soetens@fmtc.be 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 #include "TinyDemarshaller.hpp" 00040 00041 00042 // Modified tinyxml* to include it in the RTT namespace to avoid clashes 00043 // with possible other libraries. 00044 #include "tinyxml.h" 00045 00046 // This is currently not defined: 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(); // cleanup 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 //( new Property<PropertyBag>( pn, description, *pb ) ); 00200 //delete pb; 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 // it is a description of a struct that ended 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"; // override 00277 } 00278 00279 Property<PropertyBag> *prop; 00280 prop = new Property<PropertyBag>(name,"",PropertyBag(type)); 00281 00282 // take reference to bag itself ! 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 // notify start of new element 00330 this->startElement( pParent->Value(), pParent->ToElement()->FirstAttribute() ); 00331 00332 // recurse in children, if any 00333 for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) 00334 { 00335 if ( this->populateBag( pChild ) == false) 00336 return false; 00337 } 00338 00339 // notify end of element 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 // not interested in these... 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