// ********************************************************************** // // Copyright (c) 2003 - 2004 // ZeroC, Inc. // North Palm Beach, FL, USA // // All Rights Reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #include #include #include #include using namespace std; using namespace IceXML; // // ParserException // IceXML::ParserException::ParserException(const string& reason) : IceUtil::Exception(), _reason(reason) { } IceXML::ParserException::ParserException(const char* file, int line, const string& reason) : IceUtil::Exception(file, line), _reason(reason) { } string IceXML::ParserException::_name = "IceXML::ParserException"; const string& IceXML::ParserException::ice_name() const { return _name; } void IceXML::ParserException::ice_print(std::ostream& out) const { Exception::ice_print(out); if(!_reason.empty()) { out << "\n" << _reason; } else { out << ":\nXML parser exception"; } } IceUtil::Exception* IceXML::ParserException::ice_clone() const { return new ParserException(*this); } void IceXML::ParserException::ice_throw() const { throw *this; } string IceXML::ParserException::reason() const { return _reason; } // // Node // IceXML::Node::Node(const NodePtr& parent, const string& name, const string& value, int line, int column) : _parent(parent), _name(name), _value(value), _line(line), _column(column) { } IceXML::Node::~Node() { } IceXML::NodePtr IceXML::Node::getParent() const { return _parent; } string IceXML::Node::getName() const { return _name; } string IceXML::Node::getValue() const { return _value; } IceXML::NodeList IceXML::Node::getChildren() const { return NodeList(); } IceXML::Attributes IceXML::Node::getAttributes() const { return Attributes(); } string IceXML::Node::getAttribute(const string&) const { return string(); } bool IceXML::Node::addChild(const NodePtr&) { return false; } int IceXML::Node::getLine() const { return _line; } int IceXML::Node::getColumn() const { return _column; } // // Element // IceXML::Element::Element(const NodePtr& parent, const string& name, const Attributes& attributes, int line, int column) : Node(parent, name, "", line, column), _attributes(attributes) { } IceXML::Element::~Element() { } IceXML::NodeList IceXML::Element::getChildren() const { return _children; } IceXML::Attributes IceXML::Element::getAttributes() const { return _attributes; } string IceXML::Element::getAttribute(const string& name) const { Attributes::const_iterator p = _attributes.find(name); if(p != _attributes.end()) { return p->second; } return string(); } bool IceXML::Element::addChild(const NodePtr& child) { _children.push_back(child); return true; } // // Text // IceXML::Text::Text(const NodePtr& parent, const string& value, int line, int column) : Node(parent, "", value, line, column) { } IceXML::Text::~Text() { } // // Document // IceXML::Document::Document() : Node(0, "", "", 0, 0) { } IceXML::Document::~Document() { } IceXML::NodeList IceXML::Document::getChildren() const { return _children; } bool IceXML::Document::addChild(const NodePtr& child) { _children.push_back(child); return true; } // // Handler // IceXML::Handler::~Handler() { } void IceXML::Handler::error(const string& msg, int line, int column) { ostringstream out; out << "XML error at input line " << line << ", column " << column << ":" << endl << msg; throw ParserException(__FILE__, __LINE__, out.str()); } // // DocumentBuilder // namespace IceXML { class DocumentBuilder : public Handler { public: DocumentBuilder(); virtual void startElement(const string&, const Attributes&, int, int); virtual void endElement(const string&, int, int); virtual void characters(const string&, int, int); DocumentPtr getDocument() const; private: list _nodeStack; DocumentPtr _document; }; } IceXML::DocumentBuilder::DocumentBuilder() { _document = new Document; _nodeStack.push_front(_document); } void IceXML::DocumentBuilder::startElement(const string& name, const Attributes& attributes, int line, int column) { NodePtr parent = _nodeStack.front(); Element* element = new Element(parent, name, attributes, line, column); bool b = parent->addChild(element); assert(b); _nodeStack.push_front(element); } void IceXML::DocumentBuilder::endElement(const string& name, int, int) { assert(!_nodeStack.empty()); _nodeStack.pop_front(); } void IceXML::DocumentBuilder::characters(const string& data, int line, int column) { NodePtr parent = _nodeStack.front(); TextPtr text = new Text(parent, data, line, column); parent->addChild(text); } DocumentPtr IceXML::DocumentBuilder::getDocument() const { return _document; } // // expat callbacks // struct CallbackData { XML_Parser parser; Handler* handler; }; static void startElementHandler(void* data, const XML_Char* name, const XML_Char** attr) { CallbackData* cb = static_cast(data); Attributes attributes; for(int i = 0; attr[i]; i += 2) { attributes[attr[i]] = attr[i + 1]; } int line = XML_GetCurrentLineNumber(cb->parser); int column = XML_GetCurrentColumnNumber(cb->parser); cb->handler->startElement(name, attributes, line, column); } static void endElementHandler(void* data, const XML_Char* name) { CallbackData* cb = static_cast(data); int line = XML_GetCurrentLineNumber(cb->parser); int column = XML_GetCurrentColumnNumber(cb->parser); cb->handler->endElement(name, line, column); } static void characterDataHandler(void* data, const XML_Char* s, int len) { CallbackData* cb = static_cast(data); string str(s, len); int line = XML_GetCurrentLineNumber(cb->parser); int column = XML_GetCurrentColumnNumber(cb->parser); cb->handler->characters(str, line, column); } // // Parser // IceXML::DocumentPtr IceXML::Parser::parse(const string& file) { DocumentBuilder builder; parse(file, builder); return builder.getDocument(); } IceXML::DocumentPtr IceXML::Parser::parse(istream& in) { DocumentBuilder builder; parse(in, builder); return builder.getDocument(); } void IceXML::Parser::parse(const string& file, Handler& handler) { ifstream in(file.c_str()); if(!in.good()) { ostringstream out; out << "unable to open file `" << file << "'"; throw ParserException(__FILE__, __LINE__, out.str()); } parse(in, handler); } void IceXML::Parser::parse(istream& in, Handler& handler) { XML_Parser parser = XML_ParserCreate(NULL); CallbackData cb; cb.parser = parser; cb.handler = &handler; XML_SetUserData(parser, &cb); XML_SetElementHandler(parser, startElementHandler, endElementHandler); XML_SetCharacterDataHandler(parser, characterDataHandler); try { char buff[1024]; int isFinal = 0; while(!isFinal) { in.read(buff, 1024); if(in.gcount() < 1024) { isFinal = 1; } if(XML_Parse(parser, buff, in.gcount(), isFinal) != 1) { handler.error(XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)); return; } } } catch(...) { XML_ParserFree(parser); throw; } XML_ParserFree(parser); }