| [1428] | 1 | /* -*- C++ -*- */ | 
|---|
 | 2 |  | 
|---|
 | 3 | #include <iostream> | 
|---|
 | 4 | #include <string> | 
|---|
 | 5 | #include <vector> | 
|---|
 | 6 | #include <list> | 
|---|
 | 7 | #include <map> | 
|---|
| [1588] | 8 | #include <lemon/error.h> | 
|---|
| [1428] | 9 | #include <lemon/xy.h> | 
|---|
 | 10 |  | 
|---|
| [1588] | 11 | namespace lemon { | 
|---|
| [1428] | 12 |  | 
|---|
| [1588] | 13 |   class XmlWriter  | 
|---|
 | 14 |   { | 
|---|
 | 15 |     std::ostream& os; | 
|---|
 | 16 |     int level; | 
|---|
| [1428] | 17 |  | 
|---|
| [1588] | 18 |   protected: | 
|---|
 | 19 |     void indent(int level) { | 
|---|
 | 20 |       os << std::endl; | 
|---|
 | 21 |       for(int i=0;i<level;i++) os << ' '; | 
|---|
 | 22 |     } | 
|---|
 | 23 |     void tag(const std::string &_tag) { | 
|---|
 | 24 |       os << '<' << _tag << '>'; | 
|---|
 | 25 |     } | 
|---|
 | 26 |     void etag(const std::string &_tag) { | 
|---|
 | 27 |       os << "</" << _tag << '>'; | 
|---|
 | 28 |     } | 
|---|
 | 29 |     void itag(const std::string &_tag) { indent();tag(_tag); } | 
|---|
 | 30 |     void ietag(const std::string &_tag) { indent();etag(_tag); } | 
|---|
| [1428] | 31 |  | 
|---|
| [1588] | 32 |     void beginTag(const std::string &_tag) { | 
|---|
 | 33 |       itag(_tag); | 
|---|
 | 34 |       level++; | 
|---|
 | 35 |     } | 
|---|
 | 36 |     void endTag(const std::string &_tag) { | 
|---|
 | 37 |       level--; | 
|---|
 | 38 |       ietag(_tag); | 
|---|
 | 39 |     } | 
|---|
| [1428] | 40 |  | 
|---|
| [1588] | 41 |   public: | 
|---|
 | 42 |  | 
|---|
 | 43 |     void indent()  | 
|---|
 | 44 |     { | 
|---|
 | 45 |       if(level>=0) indent(level); | 
|---|
 | 46 |       else level=0; | 
|---|
 | 47 |     } | 
|---|
| [1428] | 48 |    | 
|---|
| [1588] | 49 |     ///\e | 
|---|
| [1428] | 50 |    | 
|---|
| [1588] | 51 |     ///\e | 
|---|
 | 52 |     /// | 
|---|
 | 53 |     class ContTag | 
|---|
 | 54 |     { | 
|---|
 | 55 |       XmlWriter &ix; | 
|---|
 | 56 |       const std::string _tag; | 
|---|
 | 57 |     public: | 
|---|
 | 58 |       ///\e | 
|---|
| [1428] | 59 |    | 
|---|
| [1588] | 60 |       ///\e | 
|---|
 | 61 |       /// | 
|---|
 | 62 |       ContTag(XmlWriter &_ix,const std::string &_t) : | 
|---|
 | 63 |         ix(_ix), _tag(_t) | 
|---|
 | 64 |       { | 
|---|
 | 65 |         ix.tag(_tag); | 
|---|
 | 66 |       } | 
|---|
 | 67 |       ~ContTag() { ix.etag(_tag);} | 
|---|
 | 68 |     }; | 
|---|
 | 69 |  | 
|---|
 | 70 |     class LineTag | 
|---|
| [1428] | 71 |     { | 
|---|
| [1588] | 72 |       XmlWriter &ix; | 
|---|
 | 73 |       const std::string _tag; | 
|---|
 | 74 |     public: | 
|---|
 | 75 |       ///\e | 
|---|
 | 76 |      | 
|---|
 | 77 |       ///\e | 
|---|
 | 78 |       /// | 
|---|
 | 79 |       LineTag(XmlWriter &_ix,const std::string &_t) : | 
|---|
 | 80 |         ix(_ix), _tag(_t) | 
|---|
 | 81 |       { | 
|---|
 | 82 |         ix.itag(_tag); | 
|---|
 | 83 |       } | 
|---|
 | 84 |       ~LineTag() { ix.etag(_tag);} | 
|---|
 | 85 |     }; | 
|---|
 | 86 |  | 
|---|
 | 87 |     ///\e | 
|---|
 | 88 |    | 
|---|
 | 89 |     ///\e | 
|---|
 | 90 |     /// | 
|---|
 | 91 |     class Tag | 
|---|
 | 92 |     { | 
|---|
 | 93 |       XmlWriter &ix; | 
|---|
 | 94 |       const std::string _tag; | 
|---|
 | 95 |     public: | 
|---|
 | 96 |       ///\e | 
|---|
 | 97 |    | 
|---|
 | 98 |       ///\e | 
|---|
 | 99 |       /// | 
|---|
 | 100 |       Tag(XmlWriter &_ix,const std::string &_t) : | 
|---|
 | 101 |         ix(_ix), _tag(_t) | 
|---|
 | 102 |       { | 
|---|
 | 103 |         ix.beginTag(_tag); | 
|---|
 | 104 |       } | 
|---|
 | 105 |       ~Tag() {  | 
|---|
 | 106 |         ix.endTag(_tag); | 
|---|
 | 107 |       } | 
|---|
 | 108 |     }; | 
|---|
 | 109 |        | 
|---|
 | 110 |     ///\e | 
|---|
 | 111 |    | 
|---|
 | 112 |     ///\e | 
|---|
 | 113 |     /// | 
|---|
 | 114 |     XmlWriter(std::ostream& _os) : os(_os),level(-1) {} | 
|---|
 | 115 |     ~XmlWriter() { os<< std::endl; } | 
|---|
 | 116 |    | 
|---|
 | 117 |     XmlWriter &operator()(int v)  | 
|---|
 | 118 |     {  | 
|---|
 | 119 |       os << v; | 
|---|
 | 120 |       return *this; | 
|---|
| [1428] | 121 |     } | 
|---|
| [1588] | 122 |     XmlWriter &operator()(const std::string &_tag,int v)  | 
|---|
 | 123 |     {  | 
|---|
 | 124 |       LineTag t(*this,_tag); | 
|---|
 | 125 |       (*this)(v); | 
|---|
 | 126 |       return *this; | 
|---|
 | 127 |     } | 
|---|
 | 128 |     XmlWriter &operator()(double v)  | 
|---|
 | 129 |     { | 
|---|
 | 130 |       os << v; | 
|---|
 | 131 |       return *this; | 
|---|
 | 132 |     } | 
|---|
 | 133 |     XmlWriter &operator()(const std::string &_tag,double v)  | 
|---|
 | 134 |     { | 
|---|
 | 135 |       LineTag t(*this,_tag); | 
|---|
 | 136 |       (*this)(v); | 
|---|
 | 137 |       return *this; | 
|---|
 | 138 |     } | 
|---|
 | 139 |     XmlWriter &operator()(const std::string &v) | 
|---|
 | 140 |     { | 
|---|
 | 141 |       for(std::string::const_iterator i=v.begin();i!=v.end();++i) | 
|---|
 | 142 |         switch(*i) { | 
|---|
 | 143 |         case '\\': | 
|---|
 | 144 |           os << "\\\\"; | 
|---|
 | 145 |           break; | 
|---|
 | 146 |         case '<': | 
|---|
 | 147 |           os << "\\<"; | 
|---|
 | 148 |           break; | 
|---|
 | 149 |         case '&': | 
|---|
 | 150 |           os << "\\&"; | 
|---|
 | 151 |           break; | 
|---|
 | 152 |         case '\n': | 
|---|
 | 153 |           os << "\\n"; | 
|---|
 | 154 |           break; | 
|---|
 | 155 |         default: | 
|---|
 | 156 |           os<<*i; | 
|---|
 | 157 |           break; | 
|---|
 | 158 |         } | 
|---|
 | 159 |       return *this; | 
|---|
 | 160 |     } | 
|---|
 | 161 |     XmlWriter &operator()(const std::string &_tag,const std::string &v) | 
|---|
 | 162 |     { | 
|---|
 | 163 |       LineTag t(*this,_tag); | 
|---|
 | 164 |       (*this)(v); | 
|---|
 | 165 |       return *this; | 
|---|
 | 166 |     } | 
|---|
 | 167 |     ///\e | 
|---|
 | 168 |    | 
|---|
 | 169 |     ///\e | 
|---|
 | 170 |     /// | 
|---|
 | 171 |     template<class V> | 
|---|
 | 172 |     XmlWriter &operator()(const std::string &_tag,const V &v) | 
|---|
 | 173 |     { | 
|---|
 | 174 |       Tag t(*this,_tag); | 
|---|
 | 175 |       out(*this,v); | 
|---|
 | 176 |       return *this; | 
|---|
 | 177 |     } | 
|---|
 | 178 |     ///\e | 
|---|
 | 179 |    | 
|---|
 | 180 |     ///\e | 
|---|
 | 181 |     /// | 
|---|
 | 182 |     template<class V> | 
|---|
 | 183 |     XmlWriter &operator()(const V &v) | 
|---|
 | 184 |     { | 
|---|
 | 185 |       out(*this,v); | 
|---|
 | 186 |       return *this; | 
|---|
 | 187 |     } | 
|---|
| [1428] | 188 |   }; | 
|---|
 | 189 |  | 
|---|
| [1588] | 190 |   ////////////////////////////////////////////////////////////////////// | 
|---|
 | 191 |  | 
|---|
 | 192 |   class XmlReader  | 
|---|
| [1428] | 193 |   { | 
|---|
| [1588] | 194 |     std::istream& is; | 
|---|
 | 195 |     std::string next_tag; | 
|---|
 | 196 |     int line_number; | 
|---|
 | 197 |  | 
|---|
 | 198 |     void skipWhiteSpaces() | 
|---|
 | 199 |     { | 
|---|
 | 200 |       char c; | 
|---|
 | 201 |       while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++; | 
|---|
 | 202 |       is.unget(); | 
|---|
 | 203 |     } | 
|---|
 | 204 |   protected: | 
|---|
| [1428] | 205 |     ///\e | 
|---|
| [1588] | 206 |    | 
|---|
| [1428] | 207 |     ///\e | 
|---|
 | 208 |     /// | 
|---|
| [1588] | 209 |     void useTag() {next_tag.clear();} | 
|---|
 | 210 |    | 
|---|
 | 211 |     void useTag(const std::string &_tag) { | 
|---|
 | 212 |       if(nextTag()==_tag) useTag(); | 
|---|
 | 213 |       else throw DataFormatError("",line_number,"Unexpected token name"); | 
|---|
| [1428] | 214 |     } | 
|---|
 | 215 |   public: | 
|---|
 | 216 |     ///\e | 
|---|
 | 217 |    | 
|---|
 | 218 |     ///\e | 
|---|
 | 219 |     /// | 
|---|
| [1588] | 220 |     const std::string &nextTag()  | 
|---|
| [1428] | 221 |     { | 
|---|
| [1588] | 222 |       if(next_tag.empty()) { | 
|---|
 | 223 |         char c; | 
|---|
 | 224 |         skipWhiteSpaces(); | 
|---|
 | 225 |         if(!is.get(c) || c!='<') | 
|---|
 | 226 |           throw DataFormatError("",line_number,"Bad token"); | 
|---|
 | 227 |         next_tag.clear(); | 
|---|
 | 228 |         while (is.get(c) && c!='>') next_tag.push_back(c); | 
|---|
 | 229 |         if(c!='>') | 
|---|
 | 230 |           throw DataFormatError("",line_number,"Bad token"); | 
|---|
 | 231 |       } | 
|---|
 | 232 |       return next_tag; | 
|---|
| [1428] | 233 |     } | 
|---|
 | 234 |    | 
|---|
| [1588] | 235 |     ///\e | 
|---|
| [1428] | 236 |    | 
|---|
 | 237 |     ///\e | 
|---|
 | 238 |     /// | 
|---|
| [1588] | 239 |     class Tag | 
|---|
| [1428] | 240 |     { | 
|---|
| [1588] | 241 |       XmlReader &ix; | 
|---|
 | 242 |       const std::string tag; | 
|---|
 | 243 |     public: | 
|---|
 | 244 |       ///\e | 
|---|
 | 245 |      | 
|---|
 | 246 |       ///\e | 
|---|
 | 247 |       /// | 
|---|
 | 248 |       Tag(XmlReader &_ix,const std::string &_tag) : | 
|---|
 | 249 |         ix(_ix), tag(_tag) | 
|---|
 | 250 |       { | 
|---|
 | 251 |         ix.useTag(_tag); | 
|---|
 | 252 |       } | 
|---|
 | 253 |       ~Tag() { | 
|---|
 | 254 |         if(!std::uncaught_exception())  | 
|---|
 | 255 |           ix.useTag('/'+tag); | 
|---|
 | 256 |       } | 
|---|
 | 257 |     }; | 
|---|
 | 258 |  | 
|---|
 | 259 |     ///\e | 
|---|
 | 260 |    | 
|---|
 | 261 |     ///\e | 
|---|
 | 262 |     /// | 
|---|
 | 263 |     XmlReader(std::istream& _is) : is(_is), line_number(1) {} | 
|---|
 | 264 |    | 
|---|
 | 265 |     int operator()(const std::string &tag,int &v) | 
|---|
 | 266 |     {  | 
|---|
 | 267 |       Tag t(*this,tag); | 
|---|
 | 268 |       skipWhiteSpaces(); | 
|---|
 | 269 |       if(!(is >> v)) throw DataFormatError("",line_number,"Not an 'int'"); | 
|---|
 | 270 |       return v; | 
|---|
| [1428] | 271 |     } | 
|---|
| [1588] | 272 |     double operator()(const std::string &tag,double &v)  | 
|---|
 | 273 |     { | 
|---|
 | 274 |       Tag t(*this,tag); | 
|---|
 | 275 |       skipWhiteSpaces(); | 
|---|
 | 276 |       if(!(is >> v)) | 
|---|
 | 277 |         throw DataFormatError("",line_number,"Not a 'double'"); | 
|---|
 | 278 |       return v; | 
|---|
 | 279 |     } | 
|---|
 | 280 |     std::string &operator()(const std::string &tag,std::string &v) | 
|---|
 | 281 |     { | 
|---|
 | 282 |       Tag t(*this,tag); | 
|---|
 | 283 |       v.clear(); | 
|---|
 | 284 |       char c; | 
|---|
 | 285 |       while (is.get(c) && c!='<') | 
|---|
 | 286 |         if(c=='\\') | 
|---|
 | 287 |           if(!is.get(c)) | 
|---|
 | 288 |             throw DataFormatError("",line_number,"Bad string"); | 
|---|
 | 289 |           else switch(c) { | 
|---|
 | 290 |           case 'n': | 
|---|
 | 291 |             v.push_back('\n'); | 
|---|
 | 292 |             break; | 
|---|
 | 293 |           default: | 
|---|
 | 294 |             v.push_back(c); | 
|---|
 | 295 |             break; | 
|---|
 | 296 |           } | 
|---|
 | 297 |         else { | 
|---|
 | 298 |           if(c=='\n') line_number++; | 
|---|
 | 299 |           v.push_back(c); | 
|---|
 | 300 |         } | 
|---|
 | 301 |       if(c!='<') | 
|---|
 | 302 |         throw DataFormatError("",line_number,"Unexpected eof"); | 
|---|
 | 303 |       is.unget(); | 
|---|
 | 304 |       return v; | 
|---|
 | 305 |     } | 
|---|
 | 306 |     ///\e | 
|---|
 | 307 |    | 
|---|
 | 308 |     ///\e | 
|---|
 | 309 |     /// | 
|---|
 | 310 |     template<class V> | 
|---|
 | 311 |     V &operator()(const std::string &tag,V &v) | 
|---|
 | 312 |     { | 
|---|
 | 313 |       Tag t(*this,tag); | 
|---|
 | 314 |       in(*this,v); | 
|---|
 | 315 |       return v; | 
|---|
 | 316 |     } | 
|---|
 | 317 |     ///\e | 
|---|
 | 318 |    | 
|---|
 | 319 |     ///\e | 
|---|
 | 320 |     /// | 
|---|
 | 321 |     template<class V> | 
|---|
 | 322 |     V &operator()(V &v) | 
|---|
 | 323 |     { | 
|---|
 | 324 |       in(*this,v); | 
|---|
 | 325 |       return v; | 
|---|
 | 326 |     } | 
|---|
 | 327 |     ///\e | 
|---|
 | 328 |    | 
|---|
 | 329 |     ///\e | 
|---|
 | 330 |     /// | 
|---|
 | 331 |     template<class V> | 
|---|
 | 332 |     V load(const std::string &tag) | 
|---|
 | 333 |     { | 
|---|
 | 334 |       Tag t(*this,tag); | 
|---|
 | 335 |       V v; | 
|---|
 | 336 |       (*this)(tag,v); | 
|---|
 | 337 |       return v; | 
|---|
| [1428] | 338 |     } | 
|---|
 | 339 |   }; | 
|---|
 | 340 |  | 
|---|
| [1588] | 341 |   ////////////////////////////////////////////////////////////////////// | 
|---|
 | 342 |  | 
|---|
 | 343 |   template<class A> | 
|---|
 | 344 |   void out(XmlWriter &x,const std::auto_ptr<A> &v) | 
|---|
 | 345 |   { | 
|---|
 | 346 |     x(*v); | 
|---|
 | 347 |   } | 
|---|
 | 348 |  | 
|---|
 | 349 |   template<class A> | 
|---|
 | 350 |   void in(XmlReader &x,std::auto_ptr<A> &v) | 
|---|
 | 351 |   { | 
|---|
 | 352 |     v=new A; | 
|---|
 | 353 |     x(*v); | 
|---|
 | 354 |   } | 
|---|
 | 355 |  | 
|---|
 | 356 |   ////////////////////////////// | 
|---|
 | 357 |  | 
|---|
 | 358 |   template<class A,class B> | 
|---|
 | 359 |   void out(XmlWriter &x,const std::pair<A,B> &v) | 
|---|
 | 360 |   { | 
|---|
 | 361 |     x("first",v.first); | 
|---|
 | 362 |     x("second",v.second); | 
|---|
 | 363 |   } | 
|---|
 | 364 |  | 
|---|
 | 365 |   template<class A,class B> | 
|---|
 | 366 |   void in(XmlReader &x,std::pair<A,B> &v) | 
|---|
 | 367 |   { | 
|---|
 | 368 |     x("first",v.first); | 
|---|
 | 369 |     x("second",v.second); | 
|---|
 | 370 |   } | 
|---|
 | 371 |  | 
|---|
 | 372 |   ////////////////////////////// | 
|---|
 | 373 |  | 
|---|
 | 374 |   template<class T> | 
|---|
 | 375 |   void out(XmlWriter &x,const std::list<T> &v) | 
|---|
 | 376 |   { | 
|---|
 | 377 |     for(typename std::list<T>::const_iterator it=v.begin(); | 
|---|
 | 378 |         it!=v.end();++it) x("item",*it); | 
|---|
 | 379 |   } | 
|---|
 | 380 |  | 
|---|
 | 381 |   template<class T> | 
|---|
 | 382 |   void in(XmlReader &x,std::list<T> &v) | 
|---|
 | 383 |   { | 
|---|
 | 384 |     while(x.nextTag()=="item") | 
|---|
 | 385 |       { | 
|---|
 | 386 |         v.push_back(T()); | 
|---|
 | 387 |         x("item",v.back()); | 
|---|
 | 388 |       } | 
|---|
 | 389 |   } | 
|---|
 | 390 |  | 
|---|
 | 391 |   ////////////////////////////// | 
|---|
 | 392 |  | 
|---|
 | 393 |   template<class T> | 
|---|
 | 394 |   void out(XmlWriter &x,const std::vector<T> &v) | 
|---|
 | 395 |   { | 
|---|
 | 396 |     for(typename std::vector<T>::const_iterator it=v.begin(); | 
|---|
 | 397 |         it!=v.end();++it) x("item",*it); | 
|---|
 | 398 |   } | 
|---|
 | 399 |  | 
|---|
 | 400 |   template<class T> | 
|---|
 | 401 |   void in(XmlReader &x,std::vector<T> &v) | 
|---|
 | 402 |   { | 
|---|
 | 403 |     while(x.nextTag()=="item") | 
|---|
 | 404 |       { | 
|---|
 | 405 |         v.push_back(T()); | 
|---|
 | 406 |         x("item",v.back());       | 
|---|
 | 407 |       } | 
|---|
 | 408 |   } | 
|---|
 | 409 |  | 
|---|
 | 410 |   ////////////////////////////// | 
|---|
 | 411 |  | 
|---|
 | 412 |   template<class K,class V> | 
|---|
 | 413 |   void out(XmlWriter &x,const std::map<K,V> &v) | 
|---|
 | 414 |   { | 
|---|
 | 415 |     for(typename std::map<K,V>::const_iterator it=v.begin(); | 
|---|
 | 416 |         it!=v.end();++it) x("item",*it); | 
|---|
 | 417 |   } | 
|---|
 | 418 |  | 
|---|
 | 419 |   template<class K,class V> | 
|---|
 | 420 |   void in(XmlReader &x,std::map<K,V> &v) | 
|---|
 | 421 |   { | 
|---|
 | 422 |     while(x.nextTag()=="item") | 
|---|
 | 423 |       { | 
|---|
 | 424 |         typename std::map<K,V>::value_type it; | 
|---|
 | 425 |         x("item",it); | 
|---|
 | 426 |         v.insert(it); | 
|---|
 | 427 |       } | 
|---|
 | 428 |   } | 
|---|
 | 429 |  | 
|---|
 | 430 |   ////////////////////////////// | 
|---|
 | 431 |  | 
|---|
 | 432 |   template<class T> | 
|---|
 | 433 |   void out(XmlWriter &x,const lemon::xy<T> &v) | 
|---|
 | 434 |   { | 
|---|
 | 435 |     //   x("x",v.x); | 
|---|
 | 436 |     //   x("y",v.y); | 
|---|
 | 437 |     { XmlWriter::LineTag t(x,"x"); x(v.x); } | 
|---|
 | 438 |     { XmlWriter::ContTag t(x,"y"); x(v.y); } | 
|---|
 | 439 |   } | 
|---|
 | 440 |  | 
|---|
 | 441 |   template<class T> | 
|---|
 | 442 |   void in(XmlReader &x,lemon::xy<T> &v) | 
|---|
 | 443 |   { | 
|---|
 | 444 |     x("x",v.x); | 
|---|
 | 445 |     x("y",v.y); | 
|---|
 | 446 |   } | 
|---|
 | 447 |  | 
|---|
 | 448 |   ////////////////////////////// | 
|---|
 | 449 |  | 
|---|
 | 450 |   template<class T> | 
|---|
 | 451 |   void out(XmlWriter &x,const lemon::BoundingBox<T> &v) | 
|---|
 | 452 |   { | 
|---|
 | 453 |     if(!v.empty()) { | 
|---|
 | 454 |       x("point",v.bottomLeft()); | 
|---|
 | 455 |       if(v.bottomLeft()!=v.topRight()) x("point",v.topRight()); | 
|---|
 | 456 |     } | 
|---|
 | 457 |   } | 
|---|
 | 458 |  | 
|---|
 | 459 |   template<class T> | 
|---|
 | 460 |   void in(XmlReader &x,lemon::BoundingBox<T> &v) | 
|---|
 | 461 |   { | 
|---|
 | 462 |     v.clear(); | 
|---|
 | 463 |     while(x.nextTag()=="point") { | 
|---|
 | 464 |       lemon::xy<T> co; | 
|---|
 | 465 |       x("point",co); | 
|---|
 | 466 |       v.add(co); | 
|---|
 | 467 |     } | 
|---|
 | 468 |   } | 
|---|
| [1428] | 469 |    | 
|---|
 | 470 | } | 
|---|