/* -*- C++ -*- * gui/xml.h - Part of LEMON, a generic C++ optimization library * * Copyright (C) 2006 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ #include #include #include #include #include #include #include namespace lemon { class XmlIo { bool _writeMode; public: ///Check if XmlIo is in write mode. bool write() { return _writeMode;} ///Check if XmlIo is in read mode. bool read() { return !_writeMode;} std::ostream& os; int level; protected: void indent(int level) { os << std::endl; for(int i=0;i'; } void etag(const std::string &_tag) { os << "'; } void itag(const std::string &_tag) { indent();tag(_tag); } void ietag(const std::string &_tag) { indent();etag(_tag); } void beginTag(const std::string &_tag) { itag(_tag); level++; } void endTag(const std::string &_tag) { level--; ietag(_tag); } public: ///Indent the line according to its level. ///\warning It can only be used in write mode. /// void indent() { if(write()) if(level>=0) indent(level); else level=0; else throw LogicError(); } ///Read/write a tag ///Read/write a tag. ///In write mode it does not start a new line. class ContTag { XmlIo &ix; const std::string _tag; public: ///\e ///\e /// ContTag(XmlIo &_ix,const std::string &_t) : ix(_ix), _tag(_t) { if(ix.write()) ix.tag(_tag); else ix.useTag(_tag); } ~ContTag() { if(ix.write()) ix.etag(_tag); else if(!std::uncaught_exception()) ix.useTag('/'+_tag); } }; ///Read/write a tag ///Read/write a tag. ///The whole ... will be places in a single line. class LineTag { XmlIo &ix; const std::string _tag; public: ///\e ///\e /// LineTag(XmlIo &_ix,const std::string &_t) : ix(_ix), _tag(_t) { if(ix.write()) ix.itag(_tag); else ix.useTag(_tag); } ~LineTag() { if(ix.write()) ix.etag(_tag); else if(!std::uncaught_exception()) ix.useTag('/'+_tag); } }; ///Read/write a tag ///Read/write a tag. /// class Tag { XmlIo &ix; const std::string _tag; public: ///\e ///\e /// Tag(XmlIo &_ix,const std::string &_t) : ix(_ix), _tag(_t) { if(ix.write()) ix.beginTag(_tag); else ix.useTag(_tag); } ~Tag() { if(ix.write()) ix.endTag(_tag); else if(!std::uncaught_exception()) ix.useTag('/'+_tag); } }; private: std::istream& is; std::string next_tag; int line_number; void skipWhiteSpaces() { if(write()) throw LogicError(); { char c; while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++; is.unget(); } } protected: /// Use the next tag. ///\e /// void useTag() {next_tag.clear();} ///Use the next tag and check if it is equal with \c _tag ///\e /// void useTag(const std::string &_tag) { if(nextTag()==_tag) useTag(); else throw DataFormatError("",line_number,"Unexpected token name"); } public: ///Return the next tag (if a tag follows on the stream). ///\warning It can only be used in read mode. /// const std::string &nextTag() { if(write()) throw LogicError(); else if(next_tag.empty()) { char c; skipWhiteSpaces(); if(!is.get(c) || c!='<') throw DataFormatError("",line_number,"Bad format"); next_tag.clear(); while (is.get(c) && c!='>') next_tag.push_back(c); if(c!='>') throw DataFormatError("",line_number,"Bad format"); } return next_tag; } /**********************************************************************/ ///\e ///\e /// XmlIo(std::ostream& _os) : _writeMode(true), os(_os), level(-1), is(*(std::istream*)(NULL)) {} ///\e /// XmlIo(std::istream& _is) : _writeMode(false), os(*(std::ostream*)(NULL)), is(_is), line_number(1) {} ~XmlIo() { if(write()) os<< std::endl; } XmlIo &operator()(const int &v) { if(write()) os << v; else { skipWhiteSpaces(); if(!(is >> const_cast(v))) throw DataFormatError("",line_number,"Not an 'int'"); } return *this; } XmlIo &operator()(const double &v) { if(write()) os << v; else { skipWhiteSpaces(); if(!(is >> const_cast(v))) throw DataFormatError("",line_number,"Not an 'double'"); } return *this; } XmlIo &operator()(const std::string &v) { if(write()) for(std::string::const_iterator i=v.begin();i!=v.end();++i) switch(*i) { case '\\': os << "\\\\"; break; case '<': os << "\\<"; break; case '&': os << "\\&"; break; case '\n': os << "\\n"; break; default: os<<*i; break; } else { std::string &w = const_cast(v); w.clear(); char c; while (is.get(c) && c!='<') if(c=='\\') if(!is.get(c)) throw DataFormatError("",line_number,"Bad string"); else switch(c) { case 'n': w.push_back('\n'); break; default: w.push_back(c); break; } else { if(c=='\n') line_number++; w.push_back(c); } if(c!='<') throw DataFormatError("",line_number,"Unexpected eof"); is.unget(); } return *this; } XmlIo &operator()(const std::string &_tag,const int &v) { LineTag t(*this,_tag); (*this)(v); return *this; } XmlIo &operator()(const std::string &_tag,const double &v) { LineTag t(*this,_tag); (*this)(v); return *this; } XmlIo &operator()(const std::string &_tag,const std::string &v) { LineTag t(*this,_tag); (*this)(v); return *this; } ///\e ///\e /// template XmlIo &operator()(const std::string &_tag,const V &v) { Tag t(*this,_tag); xml(*this,const_cast(v)); return *this; } ///\e ///\e /// template XmlIo &operator()(const V &v) { xml(*this,const_cast(v)); return *this; } }; ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ///\e ///\relates XmlIo /// template void xml(XmlIo &x,std::auto_ptr &v) { if(x.write()) v=new A; x(*v); } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,std::pair &v) { x("first",v.first); x("second",v.second); } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,std::list &v) { if(x.write()) for(typename std::list::const_iterator it=v.begin(); it!=v.end();++it) x("item",*it); else while(x.nextTag()=="item") { v.push_back(T()); x("item",v.back()); } } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,std::vector &v) { if(x.write()) for(typename std::vector::const_iterator it=v.begin(); it!=v.end();++it) x("item",*it); else while(x.nextTag()=="item") { v.push_back(T()); x("item",v.back()); } } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,std::map &v) { if(x.write()) for(typename std::map::const_iterator it=v.begin(); it!=v.end();++it) x("item",*it); else while(x.nextTag()=="item") { typename std::map::value_type it; x("item",it); v.insert(it); } } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,lemon::xy &v) { { XmlIo::LineTag t(x,"x"); x(v.x); } { XmlIo::ContTag t(x,"y"); x(v.y); } } ///\e ///\relates XmlIo /// template void xml(XmlIo &x,lemon::BoundingBox &v) { if(x.write()) { if(!v.empty()) { x("point",v.bottomLeft()); if(v.bottomLeft()!=v.topRight()) x("point",v.topRight()); } } else { v.clear(); while(x.nextTag()=="point") { lemon::xy co; x("point",co); v.add(co); } } } }