Orocos Real-Time Toolkit  2.5.0
CPFMarshaller.cpp
00001 /***************************************************************************
00002   tag: FMTC  Tue Mar 11 21:49:20 CET 2008  CPFMarshaller.cpp
00003 
00004                         CPFMarshaller.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 "CPFMarshaller.hpp"
00040 #include "../rtt-config.h"
00041 
00042 #include <iostream>
00043 using namespace std;
00044 namespace RTT {
00045     using namespace detail;
00046     template<class T>
00047     void CPFMarshaller<std::ostream>::doWrite( const Property<T> &v, const std::string& type )
00048     {
00049         *(this->s) <<indent << "<simple ";
00050         if ( !v.getName().empty() )
00051             *(this->s) <<"name=\"" << this->escape( v.getName() ) <<"\" ";
00052         *(this->s) << "type=\""<< type <<"\">";
00053         if ( !v.getDescription().empty() )
00054             *(this->s) << "<description>"<< this->escape( v.getDescription() ) << "</description>";
00055         *(this->s) << "<value>" << v.get() << "</value></simple>\n";
00056     }
00057 
00058     void CPFMarshaller<std::ostream>::doWrite( const Property<std::string> &v, const std::string& type )
00059     {
00060         *(this->s) <<indent << "<simple ";
00061         if ( !v.getName().empty() )
00062             *(this->s) <<"name=\"" << this->escape( v.getName() ) <<"\" ";
00063         *(this->s) << "type=\""<< type <<"\">";
00064         if ( !v.getDescription().empty() )
00065             *(this->s) << "<description>"<< this->escape( v.getDescription() ) << "</description>";
00066         *(this->s) << "<value>" << this->escape( v.get() ) << "</value></simple>\n";
00067     }
00068 
00069 
00070     void CPFMarshaller<std::ostream>::doWrite( const Property<char> &v, const std::string& type )
00071     {
00072         *(this->s) <<indent << "<simple ";
00073         if ( !v.getName().empty() )
00074             *(this->s) <<"name=\"" << this->escape( v.getName() ) <<"\" ";
00075         *(this->s) << "type=\""<< type <<"\">";
00076         if ( !v.getDescription().empty() )
00077             *(this->s) << "<description>"<< this->escape( v.getDescription() ) << "</description>";
00078         if ( v.get() == '\0' )
00079             *(this->s)<< "<value></value></simple>\n";
00080         else {
00081             std::string toescape(1, v.get());
00082             *(this->s) << "<value>" << this->escape( toescape ) << "</value></simple>\n";
00083         }
00084     }
00085 
00086 
00087     std::string CPFMarshaller<std::ostream>::escape(std::string s)
00088     {
00089         std::string::size_type n=0;
00090         // replace amps first.
00091         while ((n = s.find("&",n)) != s.npos) {
00092             s.replace(n, 1, std::string("&amp;"));
00093             n += 5;
00094         }
00095 
00096         n=0;
00097         while ((n = s.find("<",n)) != s.npos) {
00098             s.replace(n, 1, std::string("&lt;"));
00099             n += 4;
00100         }
00101 
00102         n=0;
00103         while ((n = s.find(">",n)) != s.npos) {
00104             s.replace(n, 1, std::string("&gt;"));
00105             n += 4;
00106         }
00107 
00108         // TODO: Added escapes for other XML entities
00109         return s;
00110     }
00111 
00112 
00113     void CPFMarshaller<std::ostream>::introspect(PropertyBase* pb)
00114     {
00115         if (dynamic_cast<Property<unsigned char>* >(pb) )
00116             return introspect( *static_cast<Property<unsigned char>* >(pb) );
00117         if (dynamic_cast<Property<float>* >(pb) )
00118             return introspect( *static_cast<Property<float>* >(pb) );
00119         // Since the CPFDemarshaller maps 'short' and 'ushort' to int, we don't write out shorts as it would break
00120         // lots of existing files, where users use 'short' and 'long' interchangingly.
00121         // This could be finally resolved by using a conversion constructor, but the RTT typekit does not support
00122         // shorts...
00123         // if (dynamic_cast<Property<unsigned short>* >(pb) )
00124         //  return introspect( *static_cast<Property<unsigned short>* >(pb) );
00125         // if (dynamic_cast<Property<short>* >(pb) )
00126         //  return introspect( *static_cast<Property<>* >(pb) );
00127         log(Error) << "Couldn't write "<< pb->getName() << " to XML file because the " << pb->getType() << " type is not supported by the CPF format." <<endlog();
00128         log(Error) << "If your type is a C++ struct or sequence, you can register it with a type info object." <<endlog();
00129         log(Error) << "We only support these primitive types: boolean|char|double|float|long|octet|string|ulong." <<endlog();
00130     }
00131 
00132 
00133     void CPFMarshaller<std::ostream>::introspect(Property<bool> &v)
00134     {
00135         doWrite( v, "boolean");
00136     }
00137 
00138 
00139     void CPFMarshaller<std::ostream>::introspect(Property<char> &v)
00140     {
00141         doWrite( v, "char");
00142     }
00143 
00144     void CPFMarshaller<std::ostream>::introspect(Property<unsigned char> &v)
00145     {
00146         doWrite( v, "octet");
00147     }
00148 
00149 
00150     void CPFMarshaller<std::ostream>::introspect(Property<int> &v)
00151     {
00152         doWrite( v, "long");
00153     }
00154 
00155 
00156     void CPFMarshaller<std::ostream>::introspect(Property<unsigned int> &v)
00157     {
00158         doWrite( v, "ulong");
00159     }
00160 
00161     void CPFMarshaller<std::ostream>::introspect(Property<short> &v)
00162     {
00163         doWrite( v, "short");
00164     }
00165 
00166 
00167     void CPFMarshaller<std::ostream>::introspect(Property<unsigned short> &v)
00168     {
00169         doWrite( v, "ushort");
00170     }
00171 
00172     void CPFMarshaller<std::ostream>::introspect(Property<float> &v)
00173     {
00174         (this->s)->precision(15);
00175         doWrite( v, "float");
00176     }
00177 
00178     void CPFMarshaller<std::ostream>::introspect(Property<double> &v)
00179     {
00180         (this->s)->precision(25);
00181         doWrite( v, "double");
00182     }
00183 
00184 
00185     void CPFMarshaller<std::ostream>::introspect(Property<std::string> &v)
00186     {
00187         doWrite( v, "string");
00188     }
00189 
00190 
00191     void CPFMarshaller<std::ostream>::introspect(Property<PropertyBag> &b)
00192     {
00193         PropertyBag v = b.get();
00194         *(this->s) <<indent<<"<struct name=\""<<escape(b.getName())<<"\" type=\""<< escape(v.getType())<< "\">\n";
00195         indent +="   ";
00196         if ( !b.getDescription().empty() )
00197             *(this->s) <<indent<<"<description>"  <<escape(b.getDescription()) << "</description>\n";
00198 
00199         b.value().identify(this);
00200 
00201         indent = indent.substr(0, indent.length()-3);
00202         *(this->s) <<indent<<"</struct>\n";
00203     }
00204 
00205     CPFMarshaller<std::ostream>::CPFMarshaller(std::ostream &os)
00206         : StreamProcessor<std::ostream>(os), indent("  ")
00207     {
00208     }
00209 
00210     CPFMarshaller<std::ostream>::CPFMarshaller(const std::string& filename)
00211         : StreamProcessor<std::ostream>(mfile),
00212           mfile(filename.c_str(), std::fstream::out),
00213           indent("  ")
00214     {
00215         if ( !mfile ) {
00216             s = 0;
00217             log(Error) << "Could not open file for writing: "<<filename <<endlog();
00218         }
00219     }
00220 
00221 
00222     void CPFMarshaller<std::ostream>::serialize(PropertyBase* v)
00223     {
00224         if (s)
00225             v->identify( this );
00226     }
00227 
00228 
00229     void CPFMarshaller<std::ostream>::serialize(const PropertyBag &v)
00230     {
00231         if ( !s )
00232             return;
00233         *(this->s) <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00234                    <<"<!DOCTYPE properties SYSTEM \"cpf.dtd\">\n";
00235         *(this->s) <<"<properties>\n";
00236 
00237         v.identify(this);
00238 
00239         *(this->s) << "</properties>\n";
00240     }
00241 
00242 
00243     void CPFMarshaller<std::ostream>::flush()
00244     {
00245         if (s)
00246             this->s->flush();
00247     }
00248 }
00249