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