#include "fb2xml2.h" #ifdef FB2_USE_LIBXML2 #include #include #include #include #include #include namespace XML2 { //--------------------------------------------------------------------------- // XML2::XmlReader //--------------------------------------------------------------------------- class XmlReaderLocator : public QXmlLocator { public: XmlReaderLocator(XmlReader* r) : reader(r) {} virtual int columnNumber(void) const; virtual int lineNumber(void) const; private: XmlReader* reader; }; class XmlReaderPrivate { public: ~XmlReaderPrivate(void) {} private: XmlReaderPrivate(XmlReader* reader); static void onError(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator); static int onRead(void * context, char * buffer, int len); static QString C2S(const xmlChar* text, int size = -1); bool parse(const QXmlInputSource *input); bool parse(QIODevice *input); void process(xmlTextReaderPtr reader); QScopedPointer locator; Q_DECLARE_PUBLIC(XmlReader) XmlReader* q_ptr; QXmlEntityResolver* entityresolver; QXmlDTDHandler* dtdhandler; QXmlContentHandler* contenthandler; QXmlErrorHandler* errorhandler; QXmlLexicalHandler* lexicalhandler; QXmlDeclHandler* declhandler; xmlTextReaderPtr m_reader; friend class XmlReaderLocator; }; XmlReaderPrivate::XmlReaderPrivate(XmlReader* reader) : q_ptr(reader), entityresolver(0), dtdhandler(0), contenthandler(0), errorhandler(0), lexicalhandler(0), declhandler(0), m_reader(0) { this->locator.reset(new XmlReaderLocator(reader)); } QString XmlReaderPrivate::C2S(const xmlChar* text, int size) { return QString::fromLocal8Bit(reinterpret_cast(text), size); } void XmlReaderPrivate::onError(void * arg, const char * msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) { XmlReaderPrivate* r = reinterpret_cast(arg); if (r->errorhandler) { QXmlParseException e(QString::fromLocal8Bit(msg), xmlTextReaderGetParserColumnNumber(r->m_reader), xmlTextReaderGetParserLineNumber(r->m_reader)); switch (severity) { case XML_PARSER_SEVERITY_VALIDITY_WARNING: r->errorhandler->warning(e); break; case XML_PARSER_SEVERITY_VALIDITY_ERROR: r->errorhandler->error(e); break; case XML_PARSER_SEVERITY_WARNING: r->errorhandler->warning(e); break; case XML_PARSER_SEVERITY_ERROR: r->errorhandler->error(e); break; } } } void XmlReaderPrivate::process(xmlTextReaderPtr reader) { if (!contenthandler) return; switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: { QString localName = C2S(xmlTextReaderConstLocalName(reader)); QString qName = C2S(xmlTextReaderConstName(reader)); bool empty = xmlTextReaderIsEmptyElement(reader); QXmlAttributes atts; while (xmlTextReaderMoveToNextAttribute(reader)) { QString localName = C2S(xmlTextReaderConstLocalName(reader)); QString qName = C2S(xmlTextReaderConstName(reader)); QString value = C2S(xmlTextReaderConstValue(reader)); atts.append(qName, "", localName, value); } contenthandler->startElement("", localName, qName, atts); if (empty) contenthandler->endElement("", localName, qName); } break; case XML_READER_TYPE_TEXT: { QString value = C2S(xmlTextReaderConstValue(reader)); contenthandler->characters(value); } break; case XML_READER_TYPE_END_ELEMENT: { QString localName = C2S(xmlTextReaderConstLocalName(reader)); QString qName = C2S(xmlTextReaderConstName(reader)); contenthandler->endElement("", localName, qName); } break; case XML_READER_TYPE_COMMENT: { if (lexicalhandler) { QString value = C2S(xmlTextReaderConstValue(reader)); lexicalhandler->comment(value); } } break; } } int XmlReaderPrivate::onRead(void * context, char * buffer, int len) { QIODevice *device = reinterpret_cast(context); return device->read(buffer, len); } bool XmlReaderPrivate::parse(const QXmlInputSource *input) { QByteArray arr = input->data().toUtf8(); int options = XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET; m_reader = xmlReaderForMemory(arr.constData(), arr.size(), NULL, NULL, options); if (!m_reader) return false; xmlTextReaderSetErrorHandler(m_reader, &XmlReaderPrivate::onError, this); while (xmlTextReaderRead(m_reader) == 1) process(m_reader); xmlFreeTextReader(m_reader); return true; } bool XmlReaderPrivate::parse(QIODevice *input) { int options = XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET; m_reader = xmlReaderForIO(&XmlReaderPrivate::onRead, NULL, input, NULL, NULL, options); if (!m_reader) return false; xmlTextReaderSetErrorHandler(m_reader, &XmlReaderPrivate::onError, this); while (xmlTextReaderRead(m_reader) == 1) process(m_reader); xmlFreeTextReader(m_reader); return true; } XmlReader::XmlReader(void) : d_ptr(new XmlReaderPrivate(this)) { } XmlReader::~XmlReader(void) { } bool XmlReader::feature(const QString&, bool* ok) const { if (ok) *ok = false; return false; } void XmlReader::setFeature(const QString&, bool) { } bool XmlReader::hasFeature(const QString&) const { return false; } void* XmlReader::property(const QString&, bool* ok) const { if (ok) *ok = false; return 0; } void XmlReader::setProperty(const QString&, void*) { } bool XmlReader::hasProperty(const QString&) const { return false; } void XmlReader::setEntityResolver(QXmlEntityResolver* handler) { Q_D(XmlReader); d->entityresolver = handler; } QXmlEntityResolver* XmlReader::entityResolver(void) const { const XmlReaderPrivate* d = this->d_func(); return d->entityresolver; } void XmlReader::setDTDHandler(QXmlDTDHandler* handler) { Q_D(XmlReader); d->dtdhandler = handler; } QXmlDTDHandler* XmlReader::DTDHandler(void) const { const XmlReaderPrivate* d = this->d_func(); return d->dtdhandler; } void XmlReader::setContentHandler(QXmlContentHandler* handler) { Q_D(XmlReader); d->contenthandler = handler; } QXmlContentHandler* XmlReader::contentHandler(void) const { const XmlReaderPrivate* d = this->d_func(); return d->contenthandler; } void XmlReader::setErrorHandler(QXmlErrorHandler* handler) { Q_D(XmlReader); d->errorhandler = handler; } QXmlErrorHandler* XmlReader::errorHandler(void) const { const XmlReaderPrivate* d = this->d_func(); return d->errorhandler; } void XmlReader::setLexicalHandler(QXmlLexicalHandler* handler) { Q_D(XmlReader); d->lexicalhandler = handler; } QXmlLexicalHandler* XmlReader::lexicalHandler(void) const { const XmlReaderPrivate* d = this->d_func(); return d->lexicalhandler; } void XmlReader::setDeclHandler(QXmlDeclHandler* handler) { Q_D(XmlReader); d->declhandler = handler; } QXmlDeclHandler* XmlReader::declHandler(void) const { const XmlReaderPrivate* d = this->d_func(); return d->declhandler; } bool XmlReader::parse(const QXmlInputSource& input) { return this->parse(&input); } bool XmlReader::parse(const QXmlInputSource* input) { Q_D(XmlReader); if (d->contenthandler) { d->contenthandler->setDocumentLocator(d->locator.data()); } d->parse(input); return true; } bool XmlReader::parse(QIODevice *input) { Q_D(XmlReader); if (d->contenthandler) { d->contenthandler->setDocumentLocator(d->locator.data()); } d->parse(input); return true; } int XmlReaderLocator::columnNumber(void) const { return xmlTextReaderGetParserColumnNumber(this->reader->d_func()->m_reader); } int XmlReaderLocator::lineNumber(void) const { return xmlTextReaderGetParserLineNumber(this->reader->d_func()->m_reader); } } // namespace XML2 #endif // FB2_USE_LIBXML2