diff --git a/syndication/src/parsercollection.cpp b/syndication/src/parsercollection.cpp index 10f7380e9..ab637d8a7 100644 --- a/syndication/src/parsercollection.cpp +++ b/syndication/src/parsercollection.cpp @@ -1,174 +1,206 @@ /* * This file is part of libsyndication * * Copyright (C) 2005 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "abstractdocument.h" #include "abstractparser.h" +#include "documentsource.h" #include "documentvisitor.h" #include "parsercollection.h" #include "feed.h" #include "atom/document.h" #include "atom/parser.h" #include "rdf/document.h" #include "rdf/parser.h" #include "rss2/document.h" #include "rss2/parser.h" #include "mapper/feedatomimpl.h" #include "mapper/feedrdfimpl.h" #include "mapper/feedrss2impl.h" +#include #include #include #include namespace LibSyndication { static KStaticDeleter parserregistrysd; ParserCollection* ParserCollection::m_self = 0; class ParserCollection::ParserCollectionPrivate { public: QHash parsers; + ErrorCode lastError; ParserCollectionPrivate(ParserCollection* reg) : p(reg) { docVisitor = new DocVisitor; + lastError = ParserCollection::NoError; } ~ParserCollectionPrivate() { delete docVisitor; } class DocVisitor : public LibSyndication::DocumentVisitor { public: FeedPtr createFeed(AbstractDocumentPtr ptr) { m_ptr = ptr; visit(ptr.data()); return feedptr; } bool visitAtomFeedDocument(LibSyndication::Atom::FeedDocument* document) { LibSyndication::Atom::FeedDocumentPtr tptr = LibSyndication::Atom::FeedDocumentPtr::staticCast(m_ptr); feedptr = new FeedAtomImpl(tptr); return true; } bool visitAtomEntryDocument(LibSyndication::Atom::EntryDocument* /*document*/) { // TODO return false; } bool visitRDFDocument(LibSyndication::RDF::Document* document) { LibSyndication::RDF::DocumentPtr tptr = LibSyndication::RDF::DocumentPtr::staticCast(m_ptr); feedptr = new FeedRDFImpl(tptr); return true; } bool visitRSS2Document(LibSyndication::RSS2::Document* document) { LibSyndication::RSS2::DocumentPtr tptr = LibSyndication::RSS2::DocumentPtr::staticCast(m_ptr); feedptr = new FeedRSS2Impl(tptr); return true; } FeedPtr feedptr; AbstractDocumentPtr m_ptr; }; DocVisitor* docVisitor; private: ParserCollection* p; }; ParserCollection* ParserCollection::self() { if (m_self == 0) parserregistrysd.setObject(m_self, new ParserCollection); return m_self; } ParserCollection::ParserCollection() { d = new ParserCollectionPrivate(this); registerParser(new LibSyndication::RSS2::Parser); registerParser(new LibSyndication::RDF::Parser); registerParser(new LibSyndication::Atom::Parser); } ParserCollection::~ParserCollection() { QList list = d->parsers.values(); QList::ConstIterator it = list.begin(); QList::ConstIterator end = list.end(); for ( ; it != end; ++it) delete *it; delete d; d = 0; } bool ParserCollection::registerParser(AbstractParser* parser) { if (d->parsers.contains(parser->format())) return false; d->parsers.insert(parser->format(), parser); return true; } FeedPtr ParserCollection::parse(const DocumentSource& source, const QString& formatHint) { + d->lastError = NoError; + if (d->parsers.contains(formatHint)) { if (d->parsers[formatHint]->accept(source)) - return d->docVisitor->createFeed(d->parsers[formatHint]->parse(source)); + { + AbstractDocumentPtr doc = d->parsers[formatHint]->parse(source); + if (!doc) + { + d->lastError = InvalidFormatError; + return 0; + } + + return d->docVisitor->createFeed(doc); + } } Q_FOREACH (AbstractParser* i, d->parsers) { if (i->accept(source)) { - return d->docVisitor->createFeed(i->parse(source)); + AbstractDocumentPtr doc = i->parse(source); + if (!doc) + { + d->lastError = InvalidFormatError; + return 0; + } + + return d->docVisitor->createFeed(doc); } } + if (source.asDomDocument().isNull()) + d->lastError = InvalidXmlError; + else + d->lastError = XmlNotAcceptedError; + return 0; } +ParserCollection::ErrorCode ParserCollection::lastError() const +{ + return d->lastError; +} + } // namespace LibSyndication diff --git a/syndication/src/parsercollection.h b/syndication/src/parsercollection.h index 5a8037120..8a037b04e 100644 --- a/syndication/src/parsercollection.h +++ b/syndication/src/parsercollection.h @@ -1,116 +1,146 @@ /* * This file is part of libsyndication * * Copyright (C) 2005 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef LIBSYNDICATION_PARSERCOLLECTION_H #define LIBSYNDICATION_PARSERCOLLECTION_H #include template class KSharedPtr; namespace LibSyndication { class AbstractParser; class DocumentSource; class Feed; typedef KSharedPtr FeedPtr; /** * Singleton that collects all the format-specific parser implementations. * To parse a feed source, pass it to the parse() method of this class. * * Example code: * * @code * ... * DocumentSource src(someFile.readAll()); * someFile.close(); * * FeedPtr feed = ParserCollection::self()->parse(src); * * if (feed) * { * QString title = feed->title(); * QList items = feed->items(); * ... * } * @endcode * * @author Frank Osterfeld */ class ParserCollection { public: + /** + * Error codes indicating parsing errors + */ + enum ErrorCode + { + NoError = 0, /**< No error occurred */ + InvalidXmlError = 1, /**< The XML is invalid. This is returned if no + * parser accepts the source and the DOM document + * can't be parsed. It is not returned if the source + * is not valid XML but a (non-XML) parser accepts it. + */ + XmlNotAcceptedError = 2, /**< The source is valid XML, but no parser + * accepted the it. + */ + InvalidFormatError = 3, /**< the source was accepted by a parser, but the + * actual parsing failed. As our parser + * implementations currently do not validate + * the source ("parse what you can get"), this + * code will be rarely seen. + */ + }; + /** * Singleton instance of ParserCollection. */ static ParserCollection* self(); /** destructor */ virtual ~ParserCollection(); /** * tries to parse a given source with the parsers registered. * The source is passed to the first parser that accepts it. * * @param source The source to be parsed * @param formatHint An optional hint which parser to test first. If * there is a parser with the given hint as format string (e.g., * "rss2", "atom", "rdf"...), it is asked first to accept the source. * This can avoid unnecessary AbstractParser::accept() checks and speed up * parsing. See also AbstractParser::format(). * @return The document parsed from the source, or NULL if no parser * accepted the source. */ FeedPtr parse(const DocumentSource& source, const QString& formatHint=QString::null); /** * Adds a parser to the collection. Parser::format() must be unique * in the collection. If there is already a parser with the same format * string, the parser isn't added. * * @param parser The parser to be registered * @return whether the parser was successfully registered or not. */ bool registerParser(AbstractParser* parser); + /** + * returns the error code of the last parse() call + * + * @return the last error, or NoError if parse() wasn't called yet + */ + ErrorCode lastError() const; + + protected: /** constructor */ ParserCollection(); private: ParserCollection(const ParserCollection& other) {} ParserCollection& operator=(const ParserCollection& other) {} static ParserCollection* m_self; class ParserCollectionPrivate; ParserCollectionPrivate* d; }; } // namespace LibSyndication #endif // LIBSYNDICATION_PARSERCOLLECTION_H