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