xml.h
author hegyi
Thu, 05 Jan 2006 12:30:09 +0000
branchgui
changeset 108 bf355fd6563e
parent 83 6c0db51a1d99
child 124 b8d778d4d100
permissions -rw-r--r--
Several changes. \n If new map is added to mapstorage it emits signal with the name of the new map. This was important, because from now on not only tha mapwin should be updated. \n Furthermore algobox gets a pointer to mapstorage instead of only the mapnames from it. This is important because without it it would be complicated to pass all of the required maps to algobox.
     1 /* -*- C++ -*-
     2  * gui/xml.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2006 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 #include <iostream>
    18 #include <string>
    19 #include <vector>
    20 #include <list>
    21 #include <map>
    22 #include <lemon/error.h>
    23 #include <lemon/xy.h>
    24 
    25 namespace lemon {
    26 
    27   class XmlIo 
    28   {
    29     bool _writeMode;
    30   public:
    31     ///Check if XmlIo is in write mode.
    32     bool write() { return _writeMode;}
    33     ///Check if XmlIo is in read mode.
    34     bool read() { return !_writeMode;}
    35 
    36     std::ostream& os;
    37     int level;
    38     
    39   protected:
    40     void indent(int level) {
    41       os << std::endl;
    42       for(int i=0;i<level;i++) os << ' ';
    43     }
    44     void tag(const std::string &_tag) {
    45       os << '<' << _tag << '>';
    46     }
    47     void etag(const std::string &_tag) {
    48       os << "</" << _tag << '>';
    49     }
    50     void itag(const std::string &_tag) { indent();tag(_tag); }
    51     void ietag(const std::string &_tag) { indent();etag(_tag); }
    52 
    53     void beginTag(const std::string &_tag) {
    54       itag(_tag);
    55       level++;
    56     }
    57     void endTag(const std::string &_tag) {
    58       level--;
    59       ietag(_tag);
    60     }
    61 
    62   public:
    63     ///Indent the line according to its level.
    64 
    65     ///\warning It can only be used in write mode.
    66     ///
    67     void indent()
    68     {
    69       if(write())
    70 	if(level>=0) indent(level);
    71 	else level=0;
    72       else throw LogicError();	
    73     }
    74   
    75     ///Read/write a tag
    76   
    77     ///Read/write a tag.
    78     ///In write mode it does not start a new line.
    79     class ContTag
    80     {
    81       XmlIo &ix;
    82       const std::string _tag;
    83     public:
    84       ///\e
    85   
    86       ///\e
    87       ///
    88       ContTag(XmlIo &_ix,const std::string &_t) :
    89 	ix(_ix), _tag(_t)
    90       {
    91 	if(ix.write()) ix.tag(_tag);
    92 	else ix.useTag(_tag);
    93       }
    94       ~ContTag() { 
    95 	if(ix.write()) ix.etag(_tag);
    96 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);      
    97       }
    98     };
    99 
   100     ///Read/write a tag
   101   
   102     ///Read/write a tag.
   103     ///The whole <foo> ... </foo> will be places in a single line.
   104     class LineTag
   105     {
   106       XmlIo &ix;
   107       const std::string _tag;
   108     public:
   109       ///\e
   110     
   111       ///\e
   112       ///
   113       LineTag(XmlIo &_ix,const std::string &_t) :
   114 	ix(_ix), _tag(_t)
   115       {
   116 	if(ix.write()) ix.itag(_tag);
   117 	else ix.useTag(_tag);
   118       }
   119       ~LineTag() { 
   120 	if(ix.write()) ix.etag(_tag);
   121 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   122       }
   123     };
   124 
   125     ///Read/write a tag
   126   
   127     ///Read/write a tag.
   128     ///
   129     class Tag
   130     {
   131       XmlIo &ix;
   132       const std::string _tag;
   133     public:
   134       ///\e
   135   
   136       ///\e
   137       ///
   138       Tag(XmlIo &_ix,const std::string &_t) :
   139 	ix(_ix), _tag(_t)
   140       {
   141 	if(ix.write()) ix.beginTag(_tag);
   142 	else ix.useTag(_tag);
   143       }
   144       ~Tag() {
   145 	if(ix.write()) ix.endTag(_tag);
   146 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   147       }
   148     };
   149 
   150   private:
   151     std::istream& is;
   152     std::string next_tag;
   153     int line_number;
   154 
   155     void skipWhiteSpaces()
   156     {
   157       if(write()) throw LogicError();
   158       {
   159 	char c;
   160 	while (is.get(c) && std::isspace(c,is.getloc()))
   161 	  if(c=='\n') line_number++;
   162 	is.unget();
   163       }
   164     }
   165   protected:
   166     /// Use the next tag.
   167 
   168     ///\e
   169     ///
   170     void useTag() {next_tag.clear();}
   171   
   172     ///Use the next tag and check if it is equal with \c _tag
   173   
   174     ///\e
   175     ///
   176     void useTag(const std::string &_tag) {
   177       if(nextTag()==_tag) useTag();
   178       else throw DataFormatError("",line_number,"Unexpected token name");
   179     }
   180   public:
   181     ///Return the next tag (if a tag follows on the stream).
   182   
   183     ///\warning It can only be used in read mode.
   184     ///
   185     const std::string &nextTag() 
   186     {
   187       if(write()) throw LogicError();
   188       else if(next_tag.empty()) {
   189 	char c;
   190 	skipWhiteSpaces();
   191 	if(!is.get(c) || c!='<')
   192 	  throw DataFormatError("",line_number,"Bad format");
   193 	next_tag.clear();
   194 	while (is.get(c) && c!='>') next_tag.push_back(c);
   195 	if(c!='>')
   196 	  throw DataFormatError("",line_number,"Bad format");
   197       }
   198       return next_tag;
   199     }
   200 
   201     /**********************************************************************/
   202 
   203 
   204     ///\e
   205   
   206     ///\e
   207     ///
   208     XmlIo(std::ostream& _os) : _writeMode(true), os(_os),
   209 			       level(-1),
   210 			       is(*(std::istream*)(NULL)) {}
   211     ///\e
   212     ///
   213     XmlIo(std::istream& _is) : _writeMode(false),
   214 			       os(*(std::ostream*)(NULL)), is(_is),
   215 			       line_number(1) {}
   216 
   217     ~XmlIo() { if(write()) os<< std::endl; }
   218   
   219 
   220 
   221     XmlIo &operator()(const int &v) 
   222     { 
   223       if(write()) os << v;
   224       else {
   225 	skipWhiteSpaces();
   226 	if(!(is >> const_cast<int &>(v))) 
   227 	  throw DataFormatError("",line_number,"Not an 'int'");
   228       }
   229       return *this;
   230     }
   231     XmlIo &operator()(const double &v) 
   232     {
   233       if(write()) os << v;
   234       else {
   235 	skipWhiteSpaces();
   236 	if(!(is >> const_cast<double &>(v))) 
   237 	  throw DataFormatError("",line_number,"Not an 'double'");
   238       }
   239       return *this;
   240     }
   241     XmlIo &operator()(const std::string &v)
   242     {
   243       if(write())
   244 	for(std::string::const_iterator i=v.begin();i!=v.end();++i)
   245 	  switch(*i) {
   246 	  case '\\':
   247 	    os << "\\\\";
   248 	    break;
   249 	  case '<':
   250 	    os << "\\<";
   251 	    break;
   252 	  case '&':
   253 	    os << "\\&";
   254 	    break;
   255 	  case '\n':
   256 	    os << "\\n";
   257 	    break;
   258 	  default:
   259 	    os<<*i;
   260 	    break;
   261 	  }
   262       else {
   263 	std::string &w = const_cast<std::string &>(v);
   264 	w.clear();
   265 	char c;
   266 	while (is.get(c) && c!='<')
   267 	  if(c=='\\')
   268 	    if(!is.get(c))
   269 	      throw DataFormatError("",line_number,"Bad string");
   270 	    else switch(c) {
   271 	    case 'n':
   272 	      w.push_back('\n');
   273 	      break;
   274 	    default:
   275 	      w.push_back(c);
   276 	      break;
   277 	    }
   278 	  else {
   279 	    if(c=='\n') line_number++;
   280 	    w.push_back(c);
   281 	  }
   282 	if(c!='<')
   283 	  throw DataFormatError("",line_number,"Unexpected eof");
   284 	is.unget();
   285       }
   286       return *this;
   287     }
   288 
   289 
   290     XmlIo &operator()(const std::string &_tag,const int &v) 
   291     { 
   292       LineTag t(*this,_tag);
   293       (*this)(v);
   294       return *this;
   295     }
   296     XmlIo &operator()(const std::string &_tag,const double &v) 
   297     {
   298       LineTag t(*this,_tag);
   299       (*this)(v);
   300       return *this;
   301     }
   302     XmlIo &operator()(const std::string &_tag,const std::string &v)
   303     {
   304       LineTag t(*this,_tag);
   305       (*this)(v);
   306       return *this;
   307     }
   308     ///\e
   309   
   310     ///\e
   311     ///
   312     template<class V>
   313     XmlIo &operator()(const std::string &_tag,const V &v)
   314     {
   315       Tag t(*this,_tag);
   316       xml(*this,const_cast<V &>(v));
   317       return *this;
   318     }
   319     ///\e
   320   
   321     ///\e
   322     ///
   323     template<class V>
   324     XmlIo &operator()(const V &v)
   325     {
   326       xml(*this,const_cast<V &>(v));
   327       return *this;
   328     }
   329     };
   330 
   331   //////////////////////////////////////////////////////////////////////
   332   //////////////////////////////////////////////////////////////////////
   333 
   334   ///\e
   335   
   336   ///\relates XmlIo
   337   ///
   338   template<class A>
   339   void xml(XmlIo &x,std::auto_ptr<A> &v)
   340   {
   341     if(x.write()) v=new A;
   342     x(*v);
   343   }
   344   
   345   ///\e
   346   
   347   ///\relates XmlIo
   348   ///
   349   template<class A,class B>
   350   void xml(XmlIo &x,std::pair<A,B> &v)
   351   {
   352     x("first",v.first);
   353     x("second",v.second);
   354   }
   355 
   356   ///\e
   357   
   358   ///\relates XmlIo
   359   ///
   360   template<class T>
   361   void xml(XmlIo &x,std::list<T> &v)
   362   {
   363     if(x.write())
   364       for(typename std::list<T>::const_iterator it=v.begin();
   365 	  it!=v.end();++it) x("item",*it);
   366     else while(x.nextTag()=="item")
   367       {
   368 	v.push_back(T());
   369 	x("item",v.back());
   370       }
   371   }
   372   ///\e
   373   
   374   ///\relates XmlIo
   375   ///
   376   template<class T>
   377   void xml(XmlIo &x,std::vector<T> &v)
   378   {
   379     if(x.write())
   380       for(typename std::vector<T>::const_iterator it=v.begin();
   381 	  it!=v.end();++it) x("item",*it);
   382     else while(x.nextTag()=="item")
   383       {
   384 	v.push_back(T());
   385 	x("item",v.back());      
   386       }
   387   }
   388 
   389   ///\e
   390   
   391   ///\relates XmlIo
   392   ///
   393   template<class K,class V>
   394   void xml(XmlIo &x,std::map<K,V> &v)
   395   {
   396     if(x.write()) 
   397       for(typename std::map<K,V>::const_iterator it=v.begin();
   398 	  it!=v.end();++it) x("item",*it);
   399     else while(x.nextTag()=="item")
   400       {
   401 	typename std::map<K,V>::value_type it;
   402 	x("item",it);
   403 	v.insert(it);
   404       }
   405   }
   406 
   407   ///\e
   408   
   409   ///\relates XmlIo
   410   ///
   411   template<class T>
   412   void xml(XmlIo &x,lemon::xy<T> &v)
   413   {
   414     { XmlIo::LineTag t(x,"x"); x(v.x); }
   415     { XmlIo::ContTag t(x,"y"); x(v.y); }
   416   }
   417 
   418   ///\e
   419   
   420   ///\relates XmlIo
   421   ///
   422   template<class T>
   423   void xml(XmlIo &x,lemon::BoundingBox<T> &v)
   424   {
   425     if(x.write()) {
   426       if(!v.empty()) {
   427 	x("point",v.bottomLeft());
   428 	if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
   429       }
   430     }
   431     else {
   432       v.clear();
   433       while(x.nextTag()=="point") {
   434 	lemon::xy<T> co;
   435 	x("point",co);
   436 	v.add(co);
   437       }
   438     }
   439   }
   440   
   441 }
   442