/*- * Copyright (c) 2004 Jacques A. Vidrine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace vuxml; extern "C" { static void charactersDispatcher(void *data, const XML_Char *s, int len); static void startElementDispatcher(void *data, const XML_Char *name, const XML_Char **atts); static void endElementDispatcher(void *data, const XML_Char *name); } static bool parseAttributes(const char **s, Attributes &atts) { const char **p; for (p = s; p[0] != 0 && p[1] != 0; p += 2) atts[ p[0] ] = p[1]; return true; } static bool parseNamespace(const char *s, std::string &xmlns, std::string &name) { xmlns = s; std::string::size_type n = xmlns.find_last_of(':'); if (n == std::string::npos || n+1 == std::string::npos) return false; name = xmlns.substr(n+1); xmlns.erase(n); return true; } static void charactersDispatcher(void *data, const XML_Char *s, int len) { Parser::charactersDispatcher(data, s, len); } static void startElementDispatcher(void *data, const XML_Char *s, const XML_Char **atts) { Parser::startElementDispatcher(data, s, atts); } static void endElementDispatcher(void *data, const XML_Char *name) { Parser::endElementDispatcher(data, name); } Parser * Parser::dispatcherSetup(void *data) { Parser *parser = static_cast(data); if (parser->fail_ || parser->handler_ == 0) return 0; parser->handler_->setParser(*parser); return parser; } void Parser::charactersDispatcher(void *data, const char *s, int len) { Parser *parser = dispatcherSetup(data); if (parser == 0) return; try { std::string pcdata(s, len); parser->handler_->characters(pcdata); } catch (std::exception &e) { parser->signalError(e.what()); } catch (...) { parser->signalError("unexpected exception"); } } void Parser::startElementDispatcher(void *data, const char *cname, const char **catts) { Parser *parser = dispatcherSetup(data); if (parser == 0) return; try { std::string xmlns, name; if (!parseNamespace(cname, xmlns, name)) { parser->signalError("namespace not found"); return; } Attributes atts; if (!parseAttributes(catts, atts)) { parser->signalError("bad attributes"); return; } parser->handler_->startElement(xmlns, name, atts); } catch (std::exception &e) { parser->signalError(e.what()); } catch (...) { parser->signalError("unexpected exception"); } } void Parser::endElementDispatcher(void *data, const char *cname) { Parser *parser = dispatcherSetup(data); if (parser == 0) return; try { std::string xmlns, name; if (!parseNamespace(cname, xmlns, name)) { parser->signalError("namespace not found"); return; } parser->handler_->endElement(xmlns, name); } catch (std::exception &e) { parser->signalError(e.what()); } catch (...) { parser->signalError("unexpected exception"); } } Parser::Parser() : parser_(0), handler_(0), fail_(false), line_(0) { parser_ = XML_ParserCreateNS(0, ':'); if (parser_ == 0) throw except("XML_ParserCreateNS"); XML_SetUserData(parser_, this); XML_SetCharacterDataHandler(parser_, ::charactersDispatcher); XML_SetElementHandler(parser_, ::startElementDispatcher, ::endElementDispatcher); } Parser::~Parser() { if (parser_ != 0) XML_ParserFree(parser_); } bool Parser::fail() const { return fail_; } void * Parser::getBuffer(size_t n) { void *buf = XML_GetBuffer(parser_, n); if (buf == 0) throw std::bad_alloc(); return buf; } bool Parser::parseBuffer(size_t n, bool last) { int rv; rv = XML_ParseBuffer(parser_, n, last); if (rv == 0) { fail_ = true; serr_ = std::string(); serr_ += XML_ErrorString(XML_GetErrorCode(parser_)); return false; } else if (last) return false; else return true; } void Parser::parseStream(std::istream &is) { const std::streamsize blocksize = 8192; std::streamsize n; char *buf; bool last = false; while (!fail() && !last && is.good()) { buf = static_cast(getBuffer(blocksize)); is.getline(buf, blocksize); if (is.eof()) last = true; else if (is.fail()) throw except("error reading from stream"); n = is.gcount(); if (n != blocksize-1) { ++line_; buf[n-1] = '\n'; } else if (n > 0) --n; parseBuffer(n, last); } } void Parser::setHandler(XMLHandler &handler) { handler_ = &handler; } XMLHandler & Parser::getHandler() { return *handler_; } void Parser::signalError(const std::string &serr) { fail_ = true; serr_ = serr; } const std::string & Parser::getErrorString() const { return serr_; } unsigned int Parser::getLine() const { return line_; } namespace { int lookupElement(const std::string &xmlns, const std::string &name) { if (xmlns == VUXML_NAMESPACE) return Maps::elements[name]; else if (xmlns != XHTML_NAMESPACE) return T_OTHER; else if (name == "body") return T_XHTML_BODY; else return T_XHTML; } } Element::Element(std::string &xmlns, std::string &name) { xmlns_.swap(xmlns); name_.swap(name); id_ = lookupElement(xmlns_, name_); }