// ======================================================================== // // Copyright 2009-2013 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // // you may not use this file except in compliance with the License. // // You may obtain a copy of the License at // // // // http://www.apache.org/licenses/LICENSE-2.0 // // // // Unless required by applicable law or agreed to in writing, software // // distributed under the License is distributed on an "AS IS" BASIS, // // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // // limitations under the License. // // ======================================================================== // #include "xml_parser.h" #include namespace embree { ////////////////////////////////////////////////////////////////////////////// /// XML Input ////////////////////////////////////////////////////////////////////////////// /*! parse a list of XML comments */ void parseComments(Ref >& cin) { while (cin->peek() == Token::Sym("")) cin->drop(); cin->drop(); } } /*! parse XML parameter */ void parseParm(Ref >& cin, std::map& parms) { std::string name = cin->get().Identifier(); if (cin->get() != Token::Sym("=")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \"=\" expected"); parms[name] = cin->get().String(); } /*! parse XML header */ Ref parseHeader(Ref >& cin) { Ref xml = new XML; if (cin->get() != Token::Sym("unget().Location().str()+": wrong XML header"); xml->name = cin->get().Identifier(); parseComments(cin); while (cin->peek() != Token::Sym("?>")) { parseParm(cin,xml->parms); parseComments(cin); } cin->drop(); return xml; } /*! parse XML tag */ Ref parseXML(Ref >& cin) { Ref xml = new XML; xml->loc = cin->peek().Location(); /* parse tag opening */ if (cin->get() != Token::Sym("<")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": tag expected"); xml->name = cin->get().Identifier(); parseComments(cin); while (cin->peek() != Token::Sym("/>") && cin->peek() != Token::Sym(">")) { parseParm(cin,xml->parms); parseComments(cin); } if (cin->peek() == Token::Sym("/>")) { cin->drop(); return xml; } cin->drop(); /* parse body token list */ parseComments(cin); while (cin->peek() != Token::Sym("<") && cin->peek() != Token::Sym("body.push_back(cin->get()); parseComments(cin); } /* the body also contains children */ if (cin->peek() == Token::Sym("<")) { while (cin->peek() != Token::Sym("children.push_back(parseXML(cin)); parseComments(cin); } } /* parse tag closing */ if (cin->get() != Token::Sym("unget().Location().str()+": symbol \"get() != Token::Id(xml->name)) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": closing "+xml->name+" expected"); if (cin->get() != Token::Sym(">") ) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \">\" expected"); return xml; } /* load XML from token stream */ Ref parseXML(Ref > chars, bool hasHeader = true, bool hasTail = false) { /* create lexer for XML file */ std::vector symbols; symbols.push_back(""); symbols.push_back(""); symbols.push_back(""); symbols.push_back("<"); symbols.push_back(">"); symbols.push_back("="); Ref > cin = new TokenStream(chars,TokenStream::alpha + TokenStream::ALPHA + "_", TokenStream::separators, symbols); if (hasHeader) parseHeader(cin); parseComments(cin); Ref xml = parseXML(cin); parseComments(cin); if (!hasTail) if (cin->peek() != Token::Eof()) THROW_RUNTIME_ERROR(cin->peek().Location().str()+": end of file expected"); return xml; } /*! load XML file from stream */ std::istream& operator>>(std::istream& cin, Ref& xml) { xml = parseXML(new StdStream(cin),false,true); return cin; } /*! load XML file from disk */ Ref parseXML(const FileName& fileName) { return parseXML(new FileStream(fileName),true,false); } ////////////////////////////////////////////////////////////////////////////// /// XML Output ////////////////////////////////////////////////////////////////////////////// /* indent to some hierarchy level using spaces */ void indent(std::ostream& cout, size_t depth) { for (size_t i=0; i<2*depth; i++) cout << " "; } /* store XML to a stream */ std::ostream& emitXML(std::ostream& cout, const Ref& xml, size_t depth = 0) { /* print header */ if (depth == 0) cout << "" << std::endl << std::endl; /* print tag opening */ indent(cout,depth); cout << "<" << xml->name; for (std::map::const_iterator i=xml->parms.begin(); i!=xml->parms.end(); i++) cout << " " << i->first << "=" << "\"" << i->second << "\""; if (xml->children.size() == 0 && xml->body.size() == 0) { cout << "/>" << std::endl; return cout; } cout << ">"; bool compact = xml->body.size() < 16 && xml->children.size() == 0; if (!compact) cout << std::endl; /* print token list */ if (xml->body.size()) { if (!compact) indent(cout,depth+1); for (size_t i=0; ibody.size(); i++) cout << xml->body[i] << (i!=xml->body.size()-1?" ":""); if (!compact) cout << std::endl; } /* print children */ for (size_t i=0; ichildren.size(); i++) emitXML(cout,xml->children[i],depth+1); /* print tag closing */ if (!compact) indent(cout,depth); return cout << "name << ">" << std::endl; } /* store XML to stream */ std::ostream& operator<<(std::ostream& cout, const Ref& xml) { return emitXML(cout,xml); } /*! store XML to disk */ void emitXML(const FileName& fileName, const Ref& xml) { std::ofstream cout(fileName.c_str()); if (!cout.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str() + " for writing"); emitXML(cout,xml); cout.close(); } }