alpar@1428: /* -*- C++ -*- */
alpar@1428: 
alpar@1428: #include <iostream>
alpar@1428: #include <string>
alpar@1428: #include <vector>
alpar@1428: #include <list>
alpar@1428: #include <map>
alpar@1588: #include <lemon/error.h>
alpar@1428: #include <lemon/xy.h>
alpar@1428: 
alpar@1588: namespace lemon {
alpar@1428: 
alpar@1588:   class XmlWriter 
alpar@1588:   {
alpar@1588:     std::ostream& os;
alpar@1588:     int level;
alpar@1428: 
alpar@1588:   protected:
alpar@1588:     void indent(int level) {
alpar@1588:       os << std::endl;
alpar@1588:       for(int i=0;i<level;i++) os << ' ';
alpar@1588:     }
alpar@1588:     void tag(const std::string &_tag) {
alpar@1588:       os << '<' << _tag << '>';
alpar@1588:     }
alpar@1588:     void etag(const std::string &_tag) {
alpar@1588:       os << "</" << _tag << '>';
alpar@1588:     }
alpar@1588:     void itag(const std::string &_tag) { indent();tag(_tag); }
alpar@1588:     void ietag(const std::string &_tag) { indent();etag(_tag); }
alpar@1428: 
alpar@1588:     void beginTag(const std::string &_tag) {
alpar@1588:       itag(_tag);
alpar@1588:       level++;
alpar@1588:     }
alpar@1588:     void endTag(const std::string &_tag) {
alpar@1588:       level--;
alpar@1588:       ietag(_tag);
alpar@1588:     }
alpar@1428: 
alpar@1588:   public:
alpar@1588: 
alpar@1588:     void indent() 
alpar@1588:     {
alpar@1588:       if(level>=0) indent(level);
alpar@1588:       else level=0;
alpar@1588:     }
alpar@1428:   
alpar@1588:     ///\e
alpar@1428:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     class ContTag
alpar@1588:     {
alpar@1588:       XmlWriter &ix;
alpar@1588:       const std::string _tag;
alpar@1588:     public:
alpar@1588:       ///\e
alpar@1428:   
alpar@1588:       ///\e
alpar@1588:       ///
alpar@1588:       ContTag(XmlWriter &_ix,const std::string &_t) :
alpar@1588: 	ix(_ix), _tag(_t)
alpar@1588:       {
alpar@1588: 	ix.tag(_tag);
alpar@1588:       }
alpar@1588:       ~ContTag() { ix.etag(_tag);}
alpar@1588:     };
alpar@1588: 
alpar@1588:     class LineTag
alpar@1428:     {
alpar@1588:       XmlWriter &ix;
alpar@1588:       const std::string _tag;
alpar@1588:     public:
alpar@1588:       ///\e
alpar@1588:     
alpar@1588:       ///\e
alpar@1588:       ///
alpar@1588:       LineTag(XmlWriter &_ix,const std::string &_t) :
alpar@1588: 	ix(_ix), _tag(_t)
alpar@1588:       {
alpar@1588: 	ix.itag(_tag);
alpar@1588:       }
alpar@1588:       ~LineTag() { ix.etag(_tag);}
alpar@1588:     };
alpar@1588: 
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     class Tag
alpar@1588:     {
alpar@1588:       XmlWriter &ix;
alpar@1588:       const std::string _tag;
alpar@1588:     public:
alpar@1588:       ///\e
alpar@1588:   
alpar@1588:       ///\e
alpar@1588:       ///
alpar@1588:       Tag(XmlWriter &_ix,const std::string &_t) :
alpar@1588: 	ix(_ix), _tag(_t)
alpar@1588:       {
alpar@1588: 	ix.beginTag(_tag);
alpar@1588:       }
alpar@1588:       ~Tag() { 
alpar@1588: 	ix.endTag(_tag);
alpar@1588:       }
alpar@1588:     };
alpar@1588:       
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     XmlWriter(std::ostream& _os) : os(_os),level(-1) {}
alpar@1588:     ~XmlWriter() { os<< std::endl; }
alpar@1588:   
alpar@1588:     XmlWriter &operator()(int v) 
alpar@1588:     { 
alpar@1588:       os << v;
alpar@1588:       return *this;
alpar@1428:     }
alpar@1588:     XmlWriter &operator()(const std::string &_tag,int v) 
alpar@1588:     { 
alpar@1588:       LineTag t(*this,_tag);
alpar@1588:       (*this)(v);
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     XmlWriter &operator()(double v) 
alpar@1588:     {
alpar@1588:       os << v;
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     XmlWriter &operator()(const std::string &_tag,double v) 
alpar@1588:     {
alpar@1588:       LineTag t(*this,_tag);
alpar@1588:       (*this)(v);
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     XmlWriter &operator()(const std::string &v)
alpar@1588:     {
alpar@1588:       for(std::string::const_iterator i=v.begin();i!=v.end();++i)
alpar@1588: 	switch(*i) {
alpar@1588: 	case '\\':
alpar@1588: 	  os << "\\\\";
alpar@1588: 	  break;
alpar@1588: 	case '<':
alpar@1588: 	  os << "\\<";
alpar@1588: 	  break;
alpar@1588: 	case '&':
alpar@1588: 	  os << "\\&";
alpar@1588: 	  break;
alpar@1588: 	case '\n':
alpar@1588: 	  os << "\\n";
alpar@1588: 	  break;
alpar@1588: 	default:
alpar@1588: 	  os<<*i;
alpar@1588: 	  break;
alpar@1588: 	}
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     XmlWriter &operator()(const std::string &_tag,const std::string &v)
alpar@1588:     {
alpar@1588:       LineTag t(*this,_tag);
alpar@1588:       (*this)(v);
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     template<class V>
alpar@1588:     XmlWriter &operator()(const std::string &_tag,const V &v)
alpar@1588:     {
alpar@1588:       Tag t(*this,_tag);
alpar@1588:       out(*this,v);
alpar@1588:       return *this;
alpar@1588:     }
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     template<class V>
alpar@1588:     XmlWriter &operator()(const V &v)
alpar@1588:     {
alpar@1588:       out(*this,v);
alpar@1588:       return *this;
alpar@1588:     }
alpar@1428:   };
alpar@1428: 
alpar@1588:   //////////////////////////////////////////////////////////////////////
alpar@1588: 
alpar@1588:   class XmlReader 
alpar@1428:   {
alpar@1588:     std::istream& is;
alpar@1588:     std::string next_tag;
alpar@1588:     int line_number;
alpar@1588: 
alpar@1588:     void skipWhiteSpaces()
alpar@1588:     {
alpar@1588:       char c;
alpar@1588:       while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++;
alpar@1588:       is.unget();
alpar@1588:     }
alpar@1588:   protected:
alpar@1428:     ///\e
alpar@1588:   
alpar@1428:     ///\e
alpar@1428:     ///
alpar@1588:     void useTag() {next_tag.clear();}
alpar@1588:   
alpar@1588:     void useTag(const std::string &_tag) {
alpar@1588:       if(nextTag()==_tag) useTag();
alpar@1588:       else throw DataFormatError("",line_number,"Unexpected token name");
alpar@1428:     }
alpar@1428:   public:
alpar@1428:     ///\e
alpar@1428:   
alpar@1428:     ///\e
alpar@1428:     ///
alpar@1588:     const std::string &nextTag() 
alpar@1428:     {
alpar@1588:       if(next_tag.empty()) {
alpar@1588: 	char c;
alpar@1588: 	skipWhiteSpaces();
alpar@1588: 	if(!is.get(c) || c!='<')
alpar@1588: 	  throw DataFormatError("",line_number,"Bad token");
alpar@1588: 	next_tag.clear();
alpar@1588: 	while (is.get(c) && c!='>') next_tag.push_back(c);
alpar@1588: 	if(c!='>')
alpar@1588: 	  throw DataFormatError("",line_number,"Bad token");
alpar@1588:       }
alpar@1588:       return next_tag;
alpar@1428:     }
alpar@1428:   
alpar@1588:     ///\e
alpar@1428:   
alpar@1428:     ///\e
alpar@1428:     ///
alpar@1588:     class Tag
alpar@1428:     {
alpar@1588:       XmlReader &ix;
alpar@1588:       const std::string tag;
alpar@1588:     public:
alpar@1588:       ///\e
alpar@1588:     
alpar@1588:       ///\e
alpar@1588:       ///
alpar@1588:       Tag(XmlReader &_ix,const std::string &_tag) :
alpar@1588: 	ix(_ix), tag(_tag)
alpar@1588:       {
alpar@1588: 	ix.useTag(_tag);
alpar@1588:       }
alpar@1588:       ~Tag() {
alpar@1588: 	if(!std::uncaught_exception()) 
alpar@1588: 	  ix.useTag('/'+tag);
alpar@1588:       }
alpar@1588:     };
alpar@1588: 
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     XmlReader(std::istream& _is) : is(_is), line_number(1) {}
alpar@1588:   
alpar@1588:     int operator()(const std::string &tag,int &v)
alpar@1588:     { 
alpar@1588:       Tag t(*this,tag);
alpar@1588:       skipWhiteSpaces();
alpar@1588:       if(!(is >> v)) throw DataFormatError("",line_number,"Not an 'int'");
alpar@1588:       return v;
alpar@1428:     }
alpar@1588:     double operator()(const std::string &tag,double &v) 
alpar@1588:     {
alpar@1588:       Tag t(*this,tag);
alpar@1588:       skipWhiteSpaces();
alpar@1588:       if(!(is >> v))
alpar@1588: 	throw DataFormatError("",line_number,"Not a 'double'");
alpar@1588:       return v;
alpar@1588:     }
alpar@1588:     std::string &operator()(const std::string &tag,std::string &v)
alpar@1588:     {
alpar@1588:       Tag t(*this,tag);
alpar@1588:       v.clear();
alpar@1588:       char c;
alpar@1588:       while (is.get(c) && c!='<')
alpar@1588: 	if(c=='\\')
alpar@1588: 	  if(!is.get(c))
alpar@1588: 	    throw DataFormatError("",line_number,"Bad string");
alpar@1588: 	  else switch(c) {
alpar@1588: 	  case 'n':
alpar@1588: 	    v.push_back('\n');
alpar@1588: 	    break;
alpar@1588: 	  default:
alpar@1588: 	    v.push_back(c);
alpar@1588: 	    break;
alpar@1588: 	  }
alpar@1588: 	else {
alpar@1588: 	  if(c=='\n') line_number++;
alpar@1588: 	  v.push_back(c);
alpar@1588: 	}
alpar@1588:       if(c!='<')
alpar@1588: 	throw DataFormatError("",line_number,"Unexpected eof");
alpar@1588:       is.unget();
alpar@1588:       return v;
alpar@1588:     }
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     template<class V>
alpar@1588:     V &operator()(const std::string &tag,V &v)
alpar@1588:     {
alpar@1588:       Tag t(*this,tag);
alpar@1588:       in(*this,v);
alpar@1588:       return v;
alpar@1588:     }
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     template<class V>
alpar@1588:     V &operator()(V &v)
alpar@1588:     {
alpar@1588:       in(*this,v);
alpar@1588:       return v;
alpar@1588:     }
alpar@1588:     ///\e
alpar@1588:   
alpar@1588:     ///\e
alpar@1588:     ///
alpar@1588:     template<class V>
alpar@1588:     V load(const std::string &tag)
alpar@1588:     {
alpar@1588:       Tag t(*this,tag);
alpar@1588:       V v;
alpar@1588:       (*this)(tag,v);
alpar@1588:       return v;
alpar@1428:     }
alpar@1428:   };
alpar@1428: 
alpar@1588:   //////////////////////////////////////////////////////////////////////
alpar@1588: 
alpar@1588:   template<class A>
alpar@1588:   void out(XmlWriter &x,const std::auto_ptr<A> &v)
alpar@1588:   {
alpar@1588:     x(*v);
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class A>
alpar@1588:   void in(XmlReader &x,std::auto_ptr<A> &v)
alpar@1588:   {
alpar@1588:     v=new A;
alpar@1588:     x(*v);
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class A,class B>
alpar@1588:   void out(XmlWriter &x,const std::pair<A,B> &v)
alpar@1588:   {
alpar@1588:     x("first",v.first);
alpar@1588:     x("second",v.second);
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class A,class B>
alpar@1588:   void in(XmlReader &x,std::pair<A,B> &v)
alpar@1588:   {
alpar@1588:     x("first",v.first);
alpar@1588:     x("second",v.second);
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void out(XmlWriter &x,const std::list<T> &v)
alpar@1588:   {
alpar@1588:     for(typename std::list<T>::const_iterator it=v.begin();
alpar@1588: 	it!=v.end();++it) x("item",*it);
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void in(XmlReader &x,std::list<T> &v)
alpar@1588:   {
alpar@1588:     while(x.nextTag()=="item")
alpar@1588:       {
alpar@1588: 	v.push_back(T());
alpar@1588: 	x("item",v.back());
alpar@1588:       }
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void out(XmlWriter &x,const std::vector<T> &v)
alpar@1588:   {
alpar@1588:     for(typename std::vector<T>::const_iterator it=v.begin();
alpar@1588: 	it!=v.end();++it) x("item",*it);
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void in(XmlReader &x,std::vector<T> &v)
alpar@1588:   {
alpar@1588:     while(x.nextTag()=="item")
alpar@1588:       {
alpar@1588: 	v.push_back(T());
alpar@1588: 	x("item",v.back());      
alpar@1588:       }
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class K,class V>
alpar@1588:   void out(XmlWriter &x,const std::map<K,V> &v)
alpar@1588:   {
alpar@1588:     for(typename std::map<K,V>::const_iterator it=v.begin();
alpar@1588: 	it!=v.end();++it) x("item",*it);
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class K,class V>
alpar@1588:   void in(XmlReader &x,std::map<K,V> &v)
alpar@1588:   {
alpar@1588:     while(x.nextTag()=="item")
alpar@1588:       {
alpar@1588: 	typename std::map<K,V>::value_type it;
alpar@1588: 	x("item",it);
alpar@1588: 	v.insert(it);
alpar@1588:       }
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void out(XmlWriter &x,const lemon::xy<T> &v)
alpar@1588:   {
alpar@1588:     //   x("x",v.x);
alpar@1588:     //   x("y",v.y);
alpar@1588:     { XmlWriter::LineTag t(x,"x"); x(v.x); }
alpar@1588:     { XmlWriter::ContTag t(x,"y"); x(v.y); }
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void in(XmlReader &x,lemon::xy<T> &v)
alpar@1588:   {
alpar@1588:     x("x",v.x);
alpar@1588:     x("y",v.y);
alpar@1588:   }
alpar@1588: 
alpar@1588:   //////////////////////////////
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void out(XmlWriter &x,const lemon::BoundingBox<T> &v)
alpar@1588:   {
alpar@1588:     if(!v.empty()) {
alpar@1588:       x("point",v.bottomLeft());
alpar@1588:       if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
alpar@1588:     }
alpar@1588:   }
alpar@1588: 
alpar@1588:   template<class T>
alpar@1588:   void in(XmlReader &x,lemon::BoundingBox<T> &v)
alpar@1588:   {
alpar@1588:     v.clear();
alpar@1588:     while(x.nextTag()=="point") {
alpar@1588:       lemon::xy<T> co;
alpar@1588:       x("point",co);
alpar@1588:       v.add(co);
alpar@1588:     }
alpar@1588:   }
alpar@1428:   
alpar@1428: }