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