Permalink
Cannot retrieve contributors at this time
// | |
// Copyright (c) ZeroC, Inc. All rights reserved. | |
// | |
#include <IceXML/Parser.h> | |
#include <IceUtil/FileUtil.h> | |
#include <expat.h> | |
#include <list> | |
#include <fstream> | |
using namespace std; | |
using namespace IceXML; | |
// | |
// ParserException | |
// | |
IceXML::ParserException::ParserException(const string& reason) : | |
_reason(reason) | |
{ | |
} | |
IceXML::ParserException::ParserException(const char* file, int line, const string& reason) : | |
IceUtil::ExceptionHelper<ParserException>(file, line), _reason(reason) | |
{ | |
} | |
#ifndef ICE_CPP11_COMPILER | |
IceXML::ParserException::~ParserException() throw() | |
{ | |
} | |
#endif | |
string | |
IceXML::ParserException::ice_id() const | |
{ | |
return "::IceXML::ParserException"; | |
} | |
void | |
IceXML::ParserException::ice_print(std::ostream& out) const | |
{ | |
Exception::ice_print(out); | |
if(!_reason.empty()) | |
{ | |
out << "\n" << _reason; | |
} | |
else | |
{ | |
out << ":\nXML parser exception"; | |
} | |
} | |
#ifndef ICE_CPP11_MAPPING | |
IceXML::ParserException* | |
IceXML::ParserException::ice_clone() const | |
{ | |
return new ParserException(*this); | |
} | |
#endif | |
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; | |
} | |
void | |
IceXML::Node::destroy() | |
{ | |
_parent = 0; | |
} | |
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; | |
} | |
void | |
IceXML::Element::destroy() | |
{ | |
Node::destroy(); | |
for(NodeList::iterator p = _children.begin(); p != _children.end(); ++p) | |
{ | |
(*p)->destroy(); | |
} | |
} | |
// | |
// 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; | |
} | |
void | |
IceXML::Document::destroy() | |
{ | |
Node::destroy(); | |
for(NodeList::iterator p = _children.begin(); p != _children.end(); ++p) | |
{ | |
(*p)->destroy(); | |
} | |
} | |
// | |
// 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<NodePtr> _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); | |
#ifdef NDEBUG | |
parent->addChild(element); | |
#else | |
assert(parent->addChild(element)); | |
#endif | |
_nodeStack.push_front(element); | |
} | |
void | |
IceXML::DocumentBuilder::endElement(const string&, 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; | |
}; | |
extern "C" | |
{ | |
static void | |
startElementHandler(void* data, const XML_Char* name, const XML_Char** attr) | |
{ | |
CallbackData* cb = static_cast<CallbackData*>(data); | |
Attributes attributes; | |
for(int i = 0; attr[i]; i += 2) | |
{ | |
attributes[attr[i]] = attr[i + 1]; | |
} | |
int line = static_cast<int>(XML_GetCurrentLineNumber(cb->parser)); | |
int column = static_cast<int>(XML_GetCurrentColumnNumber(cb->parser)); | |
cb->handler->startElement(name, attributes, line, column); | |
} | |
static void | |
endElementHandler(void* data, const XML_Char* name) | |
{ | |
CallbackData* cb = static_cast<CallbackData*>(data); | |
int line = static_cast<int>(XML_GetCurrentLineNumber(cb->parser)); | |
int column = static_cast<int>(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<CallbackData*>(data); | |
string str(s, static_cast<size_t>(len)); | |
int line = static_cast<int>(XML_GetCurrentLineNumber(cb->parser)); | |
int column = static_cast<int>(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) // The given filename must be UTF-8 encoded | |
{ | |
ifstream in(IceUtilInternal::streamFilename(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(ICE_NULLPTR); | |
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, static_cast<int>(in.gcount()), isFinal) != 1) | |
{ | |
handler.error(XML_ErrorString(XML_GetErrorCode(parser)), | |
static_cast<int>(XML_GetCurrentLineNumber(parser)), | |
static_cast<int>(XML_GetCurrentColumnNumber(parser))); | |
return; | |
} | |
} | |
} | |
catch(...) | |
{ | |
XML_ParserFree(parser); | |
throw; | |
} | |
XML_ParserFree(parser); | |
} |